<?php

namespace GriffinForms\Includes\Onboarding;

use GriffinForms\Admin\Sql\Form as FormSql;
use GriffinForms\Includes\Integrations\FormSettingsManager;
use GriffinForms\Traits\Singleton;

class StarterGenerator extends \GriffinForms\Format
{
    use Singleton;

    protected $starter_catalog;

    protected function setStarterCatalog()
    {
        $this->starter_catalog = StarterCatalog::getInstance();
    }

    public function createFormFromGoal(string $goal_key, array $toggle_keys = [])
    {
        $goal = $this->starter_catalog->getGoal($goal_key);
        if (!$goal) {
            return new \WP_Error('invalid_goal', __('The selected onboarding goal is invalid.', 'griffinforms-form-builder'));
        }

        $field_keys = $this->starter_catalog->getStarterFieldKeys($goal_key, $toggle_keys);
        if (empty($field_keys)) {
            return new \WP_Error('empty_starter', __('The selected starter could not be prepared.', 'griffinforms-form-builder'));
        }

        $form_data = $this->buildFormData($goal, $field_keys);
        $importer = new \GriffinForms\Includes\ImportExport\FormImport($form_data);
        $form_id = $importer->importForm();

        if (!$form_id) {
            return new \WP_Error('starter_import_failed', __('The starter form could not be created.', 'griffinforms-form-builder'));
        }

        global $wpdb;
        $wpdb->update(
            $this->config->getTable('form'),
            [
                'origin' => 'local',
                'name' => sanitize_text_field($goal['form_name']),
                'heading' => sanitize_text_field($goal['form_heading']),
                'description' => sanitize_text_field($goal['form_description'] ?? ''),
            ],
            ['id' => absint($form_id)],
            ['%s', '%s', '%s', '%s'],
            ['%d']
        );

        $configuration_result = $this->applyPostCreateConfiguration(absint($form_id), $goal_key, $field_keys);
        if (is_wp_error($configuration_result)) {
            FormSql::getInstance()->deleteForm((int) $form_id, false);
            return $configuration_result;
        }

        return absint($form_id);
    }

    public function createBlankFormWithStarterFields(string $form_name, string $form_description, array $field_keys = [])
    {
        $field_keys = $this->normalizeStarterFieldKeys($field_keys);
        $form_data = $this->buildBlankFormData($form_name, $form_description, $field_keys);
        $importer = new \GriffinForms\Includes\ImportExport\FormImport($form_data);
        $form_id = $importer->importForm();

        if (!$form_id) {
            return new \WP_Error('blank_form_import_failed', __('The blank form could not be created.', 'griffinforms-form-builder'));
        }

        return absint($form_id);
    }

    protected function buildFormData(array $goal, array $field_keys): array
    {
        $page_heading = __('Page 1', 'griffinforms-form-builder');
        $page_description = sanitize_text_field((string) ($goal['form_description'] ?? ''));

        if ((string) ($goal['starter_goal_key'] ?? '') === 'user_registration') {
            $page_heading = '';
            $page_description = '';
        }

        return [
            'name' => $goal['form_name'],
            'heading' => $goal['form_heading'],
            'description' => '',
            'formpages' => [],
            'pages' => [
                [
                    'id' => 1,
                    'name' => __('Page 1', 'griffinforms-form-builder'),
                    'heading' => $page_heading,
                    'description' => $page_description,
                    'pagerows' => [],
                    'rows' => $this->buildRows($field_keys, (string) ($goal['starter_goal_key'] ?? '')),
                ],
            ],
            'user_action' => [],
        ];
    }

    protected function buildBlankFormData(string $form_name, string $form_description, array $field_keys): array
    {
        $field_keys = $this->normalizeStarterFieldKeys($field_keys);
        $rows = !empty($field_keys)
            ? $this->buildRows($field_keys)
            : [
                [
                    'id' => 1,
                    'name' => __('Row 1', 'griffinforms-form-builder'),
                    'heading' => '',
                    'description' => '',
                    'rowcolumns' => [],
                    'columns' => [
                        [
                            'id' => 1,
                            'name' => __('Column 1', 'griffinforms-form-builder'),
                            'heading' => '',
                            'description' => '',
                            'fields' => [],
                            'width' => 12,
                            'field_data' => [],
                        ],
                    ],
                ],
            ];

        return [
            'name' => $form_name,
            'heading' => $form_name,
            'description' => $form_description,
            'formpages' => [],
            'pages' => [
                [
                    'id' => 1,
                    'name' => __('Page 1', 'griffinforms-form-builder'),
                    'heading' => '',
                    'description' => sanitize_text_field($form_description),
                    'pagerows' => [],
                    'rows' => $rows,
                ],
            ],
            'user_action' => [],
        ];
    }

    protected function buildRows(array $field_keys, string $goal_key = ''): array
    {
        if ($goal_key === 'user_registration') {
            return $this->buildRegistrationRows($field_keys);
        }

        $rows = [];
        $row_id = 1;
        $column_id = 1;
        $field_id = 1;
        $short_field_buffer = [];

        foreach ($field_keys as $field_key) {
            if ($this->isShortField($field_key)) {
                $short_field_buffer[] = $field_key;

                if (count($short_field_buffer) === 2) {
                    $rows[] = $this->buildRow($row_id++, $short_field_buffer, $column_id, $field_id);
                    $column_id += count($short_field_buffer);
                    $field_id += count($short_field_buffer);
                    $short_field_buffer = [];
                }

                continue;
            }

            if (!empty($short_field_buffer)) {
                $rows[] = $this->buildRow($row_id++, $short_field_buffer, $column_id, $field_id);
                $column_id += count($short_field_buffer);
                $field_id += count($short_field_buffer);
                $short_field_buffer = [];
            }

            $rows[] = $this->buildRow($row_id++, [$field_key], $column_id, $field_id);
            $column_id += 1;
            $field_id += 1;
        }

        if (!empty($short_field_buffer)) {
            $rows[] = $this->buildRow($row_id++, $short_field_buffer, $column_id, $field_id);
        }

        return $rows;
    }

    protected function buildRegistrationRows(array $field_keys): array
    {
        $rows = [];
        $row_id = 1;
        $column_id = 1;
        $field_id = 1;

        if (in_array('email_address', $field_keys, true)) {
            $rows[] = $this->buildRow($row_id++, ['email_address'], $column_id, $field_id);
            $column_id++;
            $field_id++;
            $field_keys = array_values(array_filter($field_keys, static function ($field_key) {
                return $field_key !== 'email_address';
            }));
        }

        if (in_array('password', $field_keys, true)) {
            $field_keys = array_values(array_filter($field_keys, static function ($field_key) {
                return $field_key !== 'password';
            }));
            $field_keys[] = 'password';
        }

        while (!empty($field_keys)) {
            if (count($field_keys) > 1 && in_array('password', $field_keys, true)) {
                $password_index = array_search('password', $field_keys, true);
                if ($password_index !== false) {
                    $chunk = array_splice($field_keys, 0, min(2, (int) $password_index));
                    if (empty($chunk)) {
                        $chunk = [array_shift($field_keys)];
                    }
                } else {
                    $chunk = array_splice($field_keys, 0, 2);
                }
            } elseif ($field_keys[0] === 'password') {
                $chunk = [array_shift($field_keys)];
            } else {
                $chunk = array_splice($field_keys, 0, 2);
            }
            $rows[] = $this->buildRow($row_id++, $chunk, $column_id, $field_id);
            $column_id += count($chunk);
            $field_id += count($chunk);
        }

        return $rows;
    }

    protected function buildRow(int $row_id, array $field_keys, int $column_start, int $field_start): array
    {
        $columns = [];

        foreach (array_values($field_keys) as $index => $field_key) {
            $width = count($field_keys) > 1 ? 6 : 12;
            $columns[] = [
                'id' => $column_start + $index,
                'name' => sprintf(__('Column %d', 'griffinforms-form-builder'), $column_start + $index),
                'heading' => '',
                'description' => '',
                'fields' => [],
                'width' => $width,
                'field_data' => [
                    $this->buildField($field_key, $field_start + $index),
                ],
            ];
        }

        return [
            'id' => $row_id,
            'name' => sprintf(__('Row %d', 'griffinforms-form-builder'), $row_id),
            'heading' => '',
            'description' => '',
            'rowcolumns' => [],
            'columns' => $columns,
        ];
    }

    protected function buildField(string $field_key, int $field_id): array
    {
        $field_definition = $this->starter_catalog->getFieldDefinition($field_key);
        if (!$field_definition) {
            return [];
        }

        $field_definition['id'] = $field_id;

        return $field_definition;
    }

    protected function isShortField(string $field_key): bool
    {
        return in_array($field_key, ['full_name', 'email_address', 'phone', 'company', 'subject', 'priority', 'first_name', 'last_name', 'username'], true);
    }

    protected function normalizeStarterFieldKeys(array $field_keys): array
    {
        $allowed = array_keys($this->starter_catalog->getBlankFormStarterFieldOptions());
        if (empty($allowed)) {
            return [];
        }

        $normalized = [];
        foreach ($field_keys as $field_key) {
            $field_key = sanitize_key((string) $field_key);
            if ($field_key === '' || !in_array($field_key, $allowed, true) || isset($normalized[$field_key])) {
                continue;
            }

            $normalized[$field_key] = $field_key;
        }

        return array_values($normalized);
    }

    protected function applyPostCreateConfiguration(int $form_id, string $goal_key, array $field_keys)
    {
        if ($form_id <= 0) {
            return new \WP_Error('invalid_form_context', __('The onboarding starter form could not be configured.', 'griffinforms-form-builder'));
        }

        if ($goal_key !== 'user_registration') {
            return true;
        }

        return $this->applyRegistrationStarterConfiguration($form_id, $field_keys);
    }

    protected function applyRegistrationStarterConfiguration(int $form_id, array $field_keys)
    {
        $field_map = $this->resolveCreatedFieldMap($form_id);
        $email_field_id = absint($field_map['email_address']['id'] ?? 0);

        if ($email_field_id <= 0) {
            return new \WP_Error('registration_starter_missing_email', __('The registration starter could not be configured because the email field was not created correctly.', 'griffinforms-form-builder'));
        }

        $username_field_id = absint($field_map['username']['id'] ?? 0);
        $password_field_id = absint($field_map['password']['id'] ?? 0);

        $rule = [
            'id' => 'wa_rule_onboarding_' . wp_generate_password(10, false, false),
            'enabled' => true,
            'email_field_id' => $email_field_id,
            'password_mode' => $password_field_id > 0 ? 'mapped_password' : 'generate_password',
            'password_field_id' => $password_field_id,
            'first_name_mode' => isset($field_map['first_name']) ? 'map_field' : 'none',
            'first_name_field_id' => absint($field_map['first_name']['id'] ?? 0),
            'last_name_mode' => isset($field_map['last_name']) ? 'map_field' : 'none',
            'last_name_field_id' => absint($field_map['last_name']['id'] ?? 0),
            'username_mode' => $username_field_id > 0 ? 'mapped_or_generate' : 'generate_only',
            'username_field_id' => $username_field_id,
            'profile_image_mode' => 'none',
            'profile_image_field_id' => 0,
            'send_confirmation_email' => false,
            'confirmation_message_id' => 0,
            'role' => 'subscriber',
            'creation_mode' => 'immediate_create',
            'existing_account_behavior' => 'error',
        ];

        $payload = [
            'mode' => 'custom',
            'settings' => [
                'rules' => [$rule],
            ],
            'updated_at' => gmdate('c'),
            'updated_by' => get_current_user_id(),
        ];

        $result = FormSettingsManager::getInstance()->saveIntegrationSettings($form_id, 'wordpress_accounts', $payload);
        if (is_wp_error($result)) {
            return new \WP_Error('registration_starter_accounts_save_failed', $result->get_error_message());
        }

        return true;
    }

    protected function resolveCreatedFieldMap(int $form_id): array
    {
        $rows = FormSql::getInstance()->fieldsInForm($form_id);
        if (!is_array($rows)) {
            return [];
        }

        $map = [];
        foreach ($rows as $row) {
            if (!is_object($row)) {
                continue;
            }

            $matched_key = $this->matchStarterFieldKey($row);
            if ($matched_key === '' || isset($map[$matched_key])) {
                continue;
            }

            $map[$matched_key] = [
                'id' => (int) ($row->id ?? 0),
                'field_type' => (string) ($row->field_type ?? ''),
            ];
        }

        return $map;
    }

    protected function matchStarterFieldKey(object $row): string
    {
        $name = sanitize_text_field((string) ($row->name ?? ''));
        $heading = sanitize_text_field((string) ($row->heading ?? ''));

        foreach (['email_address', 'first_name', 'last_name', 'username', 'password'] as $field_key) {
            $definition = $this->starter_catalog->getFieldDefinition($field_key);
            if (!$definition) {
                continue;
            }

            $expected_name = sanitize_text_field((string) ($definition['name'] ?? ''));
            $expected_heading = sanitize_text_field((string) ($definition['heading'] ?? ''));

            if ($name === $expected_name && $heading === $expected_heading) {
                return $field_key;
            }
        }

        return '';
    }
}
