<?php

namespace GriffinForms\Includes\Ai\PromptRegistry;

use GriffinForms\Admin\Sql\Format;
use GriffinForms\Includes\Notifications\NotificationChannelRegistry;

class StructureSnapshotBuilder
{
    protected Format $format_sql;

    public function __construct()
    {
        $this->format_sql = Format::getInstance();
    }

    public function buildFromForm(int $form_id): array
    {
        $form = $this->format_sql->itemValues($form_id, 'form', ['name', 'heading', 'description', 'formpages', 'submit_label', 'notifications']);
        if (!is_object($form)) {
            return $this->emptySnapshot();
        }

        $snapshot = [
            'form' => [
                'name' => sanitize_text_field((string) ($form->name ?? '')),
                'heading' => sanitize_text_field((string) ($form->heading ?? '')),
                'description' => sanitize_textarea_field((string) ($form->description ?? '')),
                'submit_label' => sanitize_text_field((string) ($form->submit_label ?? 'Submit')),
                'has_autoresponder' => $this->detectAutoresponder($form),
            ],
            'pages' => [],
            'fields' => [],
        ];

        $page_ids = $this->decodeValue($form->formpages ?? []);
        foreach (array_values((array) $page_ids) as $page_index => $page_id) {
            $page = $this->format_sql->itemValues(absint($page_id), 'formpage', ['name', 'heading', 'description', 'pagerows', 'previous_label', 'next_label']);
            if (!is_object($page)) {
                continue;
            }

            $page_name = sanitize_text_field((string) ($page->name ?? ''));
            $page_snapshot = [
                'item_id' => absint($page_id),
                'name' => $page_name,
                'heading' => sanitize_text_field((string) ($page->heading ?? '')),
                'description' => sanitize_textarea_field((string) ($page->description ?? '')),
                'previous_label' => sanitize_text_field((string) ($page->previous_label ?? 'Previous')),
                'next_label' => sanitize_text_field((string) ($page->next_label ?? 'Next')),
                'page_label' => sprintf('Page %d', $page_index + 1),
                'rows' => [],
                'signature' => $this->pageSignature($page_name, $page_index),
            ];

            $row_ids = $this->decodeValue($page->pagerows ?? []);
            foreach (array_values((array) $row_ids) as $row_index => $row_id) {
                $row = $this->format_sql->itemValues(absint($row_id), 'pagerow', ['name', 'heading', 'description', 'rowcolumns']);
                if (!is_object($row)) {
                    continue;
                }

                $row_snapshot = [
                    'item_id' => absint($row_id),
                    'name' => sanitize_text_field((string) ($row->name ?? '')),
                    'heading' => sanitize_text_field((string) ($row->heading ?? '')),
                    'description' => sanitize_textarea_field((string) ($row->description ?? '')),
                    'row_label' => sprintf('Row %d', $row_index + 1),
                    'columns' => [],
                ];

                $column_ids = $this->decodeValue($row->rowcolumns ?? []);
                foreach (array_values((array) $column_ids) as $column_index => $column_id) {
                    $column = $this->format_sql->itemValues(absint($column_id), 'rowcolumn', ['name', 'width', 'fields']);
                    if (!is_object($column)) {
                        continue;
                    }

                    $column_snapshot = [
                        'item_id' => absint($column_id),
                        'name' => sanitize_text_field((string) ($column->name ?? '')),
                        'column_label' => sprintf('Column %d', $column_index + 1),
                        'width' => absint($column->width ?? 12),
                        'fields' => [],
                    ];

                    $field_ids = $this->decodeValue($column->fields ?? []);
                    foreach (array_values((array) $field_ids) as $field_index => $field_id) {
                        $field = $this->format_sql->itemValues(absint($field_id), 'field', ['field_type', 'name', 'heading', 'description', 'placeholder', 'is_required', 'field_options', 'field_settings', 'validations']);
                        if (!is_object($field)) {
                            continue;
                        }

                        $name = sanitize_text_field((string) ($field->name ?? ''));
                        $label = sanitize_text_field((string) ($field->heading ?? ''));
                        if ($label === '') {
                            $label = $this->humanizeIdentifierLabel($name);
                        }
                        $field_snapshot = [
                            'item_id' => absint($field_id),
                            'field_type' => sanitize_key((string) ($field->field_type ?? '')),
                            'name' => $name,
                            'label' => $label,
                            'description' => sanitize_textarea_field((string) ($field->description ?? '')),
                            'placeholder' => sanitize_text_field((string) ($field->placeholder ?? '')),
                            'required' => !empty($field->is_required),
                            'field_settings' => $this->normalizeFieldSettings($field->field_settings ?? [], sanitize_key((string) ($field->field_type ?? ''))),
                            'validations' => $this->normalizeFieldValidations($field->validations ?? [], sanitize_key((string) ($field->field_type ?? ''))),
                            'options' => $this->normalizeOptions(
                                sanitize_key((string) ($field->field_type ?? '')),
                                $this->decodeValue($field->field_options ?? [])
                            ),
                            'page_index' => $page_index,
                            'row_index' => $row_index,
                            'column_index' => $column_index,
                            'field_index' => $field_index,
                            'page_name' => $page_name,
                            'page_label' => sprintf('Page %d', $page_index + 1),
                            'row_label' => sprintf('Row %d', $row_index + 1),
                            'column_label' => sprintf('Column %d', $column_index + 1),
                        ];
                        $field_snapshot['signature'] = $this->fieldSignature($field_snapshot);

                        $column_snapshot['fields'][] = $field_snapshot;
                        $snapshot['fields'][] = $field_snapshot;
                    }

                    $row_snapshot['columns'][] = $column_snapshot;
                }

                $page_snapshot['rows'][] = $row_snapshot;
            }

            $snapshot['pages'][] = $page_snapshot;
        }

        return $snapshot;
    }

    public function buildFromSchema(array $schema): array
    {
        $form = (array) ($schema['form'] ?? []);
        $snapshot = [
            'form' => [
                'name' => sanitize_text_field((string) ($form['name'] ?? '')),
                'heading' => sanitize_text_field((string) ($form['heading'] ?? '')),
                'description' => sanitize_textarea_field((string) ($form['description'] ?? '')),
                'submit_label' => sanitize_text_field((string) ($form['submit_label'] ?? 'Submit')),
            ],
            'pages' => [],
            'fields' => [],
        ];

        foreach (array_values((array) ($schema['pages'] ?? [])) as $page_index => $page_schema) {
            $page_name = sanitize_text_field((string) ($page_schema['name'] ?? ''));
            $page_snapshot = [
                'name' => $page_name,
                'description' => sanitize_textarea_field((string) ($page_schema['description'] ?? '')),
                'previous_label' => sanitize_text_field((string) ($page_schema['previous_label'] ?? 'Previous')),
                'next_label' => sanitize_text_field((string) ($page_schema['next_label'] ?? 'Next')),
                'page_label' => sprintf('Page %d', $page_index + 1),
                'rows' => [],
                'signature' => $this->pageSignature($page_name, $page_index),
            ];

            foreach (array_values((array) ($page_schema['rows'] ?? [])) as $row_index => $row_schema) {
                $row_snapshot = [
                    'row_label' => sprintf('Row %d', $row_index + 1),
                    'columns' => [],
                ];

                foreach (array_values((array) ($row_schema['columns'] ?? [])) as $column_index => $column_schema) {
                    $column_snapshot = [
                        'column_label' => sprintf('Column %d', $column_index + 1),
                        'width' => absint($column_schema['width'] ?? 12),
                        'fields' => [],
                    ];

                    foreach (array_values((array) ($column_schema['fields'] ?? [])) as $field_index => $field_schema) {
                        $field_snapshot = [
                            'field_type' => sanitize_key((string) ($field_schema['field_type'] ?? '')),
                            'label' => sanitize_text_field((string) ($field_schema['label'] ?? '')),
                            'description' => sanitize_textarea_field((string) ($field_schema['description'] ?? '')),
                            'placeholder' => sanitize_text_field((string) ($field_schema['placeholder'] ?? '')),
                            'required' => !empty($field_schema['required']),
                            'validations' => $this->normalizeFieldValidations($field_schema['validations'] ?? [], sanitize_key((string) ($field_schema['field_type'] ?? ''))),
                            'options' => $this->normalizeOptions(
                                sanitize_key((string) ($field_schema['field_type'] ?? '')),
                                (array) ($field_schema['options'] ?? [])
                            ),
                            'page_index' => $page_index,
                            'row_index' => $row_index,
                            'column_index' => $column_index,
                            'field_index' => $field_index,
                            'page_name' => $page_name,
                            'page_label' => sprintf('Page %d', $page_index + 1),
                            'row_label' => sprintf('Row %d', $row_index + 1),
                            'column_label' => sprintf('Column %d', $column_index + 1),
                        ];
                        $field_snapshot['signature'] = $this->fieldSignature($field_snapshot);

                        $column_snapshot['fields'][] = $field_snapshot;
                        $snapshot['fields'][] = $field_snapshot;
                    }

                    $row_snapshot['columns'][] = $column_snapshot;
                }

                $page_snapshot['rows'][] = $row_snapshot;
            }

            $snapshot['pages'][] = $page_snapshot;
        }

        return $snapshot;
    }

    protected function normalizeOptions(string $field_type, $options): array
    {
        if (!is_array($options) || empty($options)) {
            return [];
        }

        if (in_array($field_type, ['inputcheckbox', 'inputradio'], true)) {
            $normalized_groups = [];

            foreach ($options as $group_index => $group) {
                $normalized_group = [
                    'column' => is_numeric($group_index) ? absint($group_index) + 1 : count($normalized_groups) + 1,
                    'options' => [],
                ];

                if (is_array($group) && isset($group['options']) && is_array($group['options'])) {
                    foreach ($group['options'] as $option) {
                        $label = sanitize_text_field((string) ($option['label'] ?? ''));
                        $value = sanitize_text_field((string) ($option['value'] ?? ''));

                        if ($label === '' || $value === '') {
                            continue;
                        }

                        $normalized_group['options'][] = [
                            'label' => $label,
                            'value' => $value,
                        ];
                    }
                } elseif (is_array($group)) {
                    foreach ($group as $nested_label => $nested_value) {
                        if (is_array($nested_value)) {
                            $label = sanitize_text_field((string) ($nested_value['label'] ?? ''));
                            $value = sanitize_text_field((string) ($nested_value['value'] ?? ''));
                        } else {
                            $label = sanitize_text_field((string) $nested_label);
                            $value = sanitize_text_field((string) $nested_value);
                        }

                        if ($label === '' || $value === '') {
                            continue;
                        }

                        $normalized_group['options'][] = [
                            'label' => $label,
                            'value' => $value,
                        ];
                    }
                }

                if (!empty($normalized_group['options'])) {
                    $normalized_groups[] = $normalized_group;
                }
            }

            return $normalized_groups;
        }

        if ($field_type === 'selectfield') {
            $normalized_groups = [];
            foreach ($options as $group_name => $group_options) {
                if (!is_array($group_options) || empty($group_options)) {
                    continue;
                }

                $group_name = sanitize_text_field((string) $group_name);
                $group_map = [];
                foreach ($group_options as $option_label => $option_value) {
                    if (is_array($option_value)) {
                        $label = sanitize_text_field((string) ($option_value['label'] ?? ''));
                        $value = sanitize_text_field((string) ($option_value['value'] ?? ''));
                    } else {
                        $label = sanitize_text_field((string) $option_label);
                        $value = sanitize_text_field((string) $option_value);
                    }

                    if ($label === '' || $value === '') {
                        continue;
                    }

                    $group_map[$label] = $value;
                }

                if (!empty($group_map)) {
                    $normalized_groups[$group_name] = $group_map;
                }
            }

            return $normalized_groups;
        }

        $normalized = [];
        foreach ($options as $key => $option) {
            if (is_array($option) && isset($option['label'], $option['value'])) {
                $normalized[] = [
                    'label' => sanitize_text_field((string) $option['label']),
                    'value' => sanitize_text_field((string) $option['value']),
                ];
                continue;
            }

            if (is_array($option)) {
                foreach ($option as $nested_label => $nested_value) {
                    $normalized[] = [
                        'label' => sanitize_text_field((string) $nested_label),
                        'value' => sanitize_text_field((string) $nested_value),
                    ];
                }
                continue;
            }

            if (is_string($key)) {
                $normalized[] = [
                    'label' => sanitize_text_field((string) $key),
                    'value' => sanitize_text_field((string) $option),
                ];
            }
        }

        return $normalized;
    }

    protected function normalizeFieldValidations($validations, string $field_type = ''): array
    {
        if (is_string($validations)) {
            $validations = maybe_unserialize($validations);
        }

        if (!is_array($validations) || empty($validations)) {
            return [];
        }

        $normalized = [];
        foreach ($validations as $key => $value) {
            $semantic_key = $this->semanticValidationKey(sanitize_key((string) $key), $field_type);
            $normalized[$semantic_key] = $this->normalizeValidationValue($value, $semantic_key, $field_type);
        }

        return array_filter($normalized, static fn($value) => $value !== null && $value !== '' && $value !== []);
    }

    protected function normalizeFieldSettings($field_settings, string $field_type = ''): array
    {
        if (is_string($field_settings)) {
            $field_settings = maybe_unserialize($field_settings);
        }

        if (!is_array($field_settings) || empty($field_settings)) {
            return [];
        }

        $normalized = [];
        foreach ($field_settings as $key => $value) {
            $semantic_key = $this->semanticFieldSettingKey(sanitize_key((string) $key), $field_type);
            $normalized[$semantic_key] = $this->normalizeFieldSettingValue($value, $semantic_key, $field_type);
        }

        return array_filter($normalized, static fn($value) => $value !== null && $value !== '' && $value !== []);
    }

    protected function semanticFieldSettingKey(string $key, string $field_type = ''): string
    {
        return $key;
    }

    protected function normalizeFieldSettingValue($value, string $semantic_key = '', string $field_type = '')
    {
        if (is_array($value)) {
            $normalized = [];
            foreach ($value as $key => $item) {
                $normalized[$this->semanticFieldSettingKey(sanitize_key((string) $key), $field_type)] = $this->normalizeFieldSettingValue($item, (string) $key, $field_type);
            }

            return array_filter($normalized, static fn($item) => $item !== null && $item !== '' && $item !== []);
        }

        if (is_bool($value) || is_int($value) || is_float($value)) {
            return $value;
        }

        $value = sanitize_text_field((string) $value);
        return $value === '' ? null : $value;
    }

    protected function semanticValidationKey(string $key, string $field_type = ''): string
    {
        if ($field_type === 'inputurl') {
            return match ($key) {
                'restricted_tld' => 'allowed_tlds',
                'excluded_tld' => 'blocked_tlds',
                default => $key,
            };
        }

        if ($field_type === 'inputphone' && $key === 'allowed_country_codes') {
            return 'allowed_country_codes';
        }

        return $key;
    }

    protected function normalizeValidationValue($value, string $semantic_key = '', string $field_type = '')
    {
        if (is_array($value)) {
            if ($semantic_key === 'allowed_tlds' || $semantic_key === 'blocked_tlds' || $semantic_key === 'allowed_country_codes') {
                return array_values(array_filter(array_map('sanitize_text_field', array_map(static fn($item) => (string) $item, $value))));
            }

            return array_map([$this, 'normalizeValidationValue'], $value);
        }

        if (is_bool($value) || is_int($value) || is_float($value)) {
            return $value;
        }

        return sanitize_text_field((string) $value);
    }

    protected function pageSignature(string $page_name, int $page_index): string
    {
        $normalized_name = $this->normalizeText($page_name);
        if ($normalized_name !== '') {
            return 'page:' . $normalized_name;
        }

        return 'page_index:' . $page_index;
    }

    protected function fieldSignature(array $field): string
    {
        $label = $this->normalizeText((string) ($field['label'] ?? ''));
        $field_type = sanitize_key((string) ($field['field_type'] ?? ''));

        if ($label !== '') {
            return $field_type . '|' . $label;
        }

        $placeholder = $this->normalizeText((string) ($field['placeholder'] ?? ''));
        if ($placeholder !== '') {
            return $field_type . '|placeholder:' . $placeholder;
        }

        return $field_type . '|page:' . absint($field['page_index'] ?? 0) . '|row:' . absint($field['row_index'] ?? 0) . '|col:' . absint($field['column_index'] ?? 0) . '|slot:' . absint($field['field_index'] ?? 0);
    }

    protected function normalizeText(string $value): string
    {
        return strtolower(trim(preg_replace('/\s+/', ' ', wp_strip_all_tags($value))));
    }

    protected function humanizeIdentifierLabel(string $value): string
    {
        $value = trim($value);
        if ($value === '') {
            return '';
        }

        $value = preg_replace('/[_-]+/', ' ', strtolower($value));
        $value = preg_replace('/\s+/', ' ', trim($value));
        if ($value === '') {
            return '';
        }

        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
    }

    protected function decodeValue($value)
    {
        if (is_array($value)) {
            return $value;
        }

        if (!is_string($value) || $value === '') {
            return $value;
        }

        $maybe_unserialized = maybe_unserialize($value);
        if ($maybe_unserialized !== $value || $value === 'b:0;') {
            return $maybe_unserialized;
        }

        $decoded_json = json_decode($value, true);
        if (json_last_error() === JSON_ERROR_NONE) {
            return $decoded_json;
        }

        return $value;
    }

    protected function emptySnapshot(): array
    {
        return [
            'form' => ['name' => '', 'description' => ''],
            'pages' => [],
            'fields' => [],
        ];
    }

    protected function detectAutoresponder($form): bool
    {
        $notifications = NotificationChannelRegistry::resolveFormNotifications($form);
        $initial = (array) ($notifications['form_submission']['initial_submission'] ?? []);
        foreach ($initial as $entry) {
            if (!is_array($entry) || ($entry['channel'] ?? '') !== 'email') {
                continue;
            }
            foreach ((array) ($entry['recipients'] ?? []) as $recipient) {
                if (is_array($recipient) && ($recipient['type'] ?? '') === 'field') {
                    return true;
                }
            }
        }
        return false;
    }
}
