<?php

namespace GriffinForms\Includes\ImportExport;

use GriffinForms\Includes\Integrations\FormSettingsManager;

class FormImport extends \GriffinForms\Includes\ImportExport\Format
{
    protected $form_data;
    protected $wpdb;
    protected $id_mapping = [];

    public function __construct($form_data) {
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->form_data = $form_data;
        $this->setAll();
    }
































// Normalize conditional logic structure (ensure required keys)
    protected function normalizeConditionalLogic($logic) {
        // Decode if needed
        if (is_string($logic)) {
            $decoded = json_decode($logic, true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $logic = $decoded;
            } else {
                $maybe = maybe_unserialize($logic);
                if ($maybe !== false || $logic === 'b:0;') {
                    $logic = $maybe;
            }
            }
        }
        if (!is_array($logic)) {
            return $logic;
        }
        // If top-level is a list of rule groups, ensure 'any' exists in each
        foreach ($logic as $idx => &$group) {
            if (is_array($group)) {
                if (!array_key_exists('any', $group)) {
                    $group['any'] = [];
                }
            }
        }
        unset($group);
        return $logic;
    }

    // Recursively remap old IDs to new IDs in conditional logic
    protected function remapConditionalLogicIds($logic) {
        // Decode if string
        if (is_string($logic)) {
            $decoded = json_decode($logic, true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $logic = $decoded;
            } else {
                $maybe = maybe_unserialize($logic);
                if ($maybe !== false || $logic === 'b:0;') {
                    $logic = $maybe;
                }
            }
        }
        if (!is_array($logic) || empty($logic)) {
            return $logic;
        }
        return $this->remapIdsRecursive($logic);
    }

    // Recursively replace old IDs with new IDs in nested arrays
    protected function remapIdsRecursive($data) {
        if (!is_array($data)) {
            return $data;
        }

        // If this node itself carries an item + item_id pair, map via that context
        if (isset($data['item']) && isset($data['item_id'])) {
            $type = strtolower((string)$data['item']);
            $oldId = $data['item_id'];
            if (is_numeric($oldId) && isset($this->id_mapping[$type][(int)$oldId])) {
                $data['item_id'] = (string)$this->id_mapping[$type][(int)$oldId];
            }
        }

        $remapped = [];
        foreach ($data as $key => $value) {
            // Direct ID fields like field_id, page_id, row_id, column_id, item_id
            if (is_string($key) && $this->isIdField($key) && (is_numeric($value) || (is_string($value) && is_numeric($value)))) {
                $remapped[$key] = $this->getNewId($key, $value, $data);
            } elseif (is_array($value)) {
                $remapped[$key] = $this->remapIdsRecursive($value);
            } else {
                $remapped[$key] = $value;
            }
        }
        return $remapped;
    }

    // Check if a key represents an ID field
    protected function isIdField($key) {
        $id_fields = ['field_id', 'page_id', 'row_id', 'column_id', 'fieldId', 'pageId', 'rowId', 'columnId', 'item_id', 'itemId'];
        return in_array($key, $id_fields, true);
    }

    // Get the new ID from mapping or return original (optionally using node context)
    protected function getNewId($key, $old_id, $node = []) {
        $type = null;
        // If the node tells us the item type, prefer that mapping for item_id
        if (($key === 'item_id' || $key === 'itemId') && isset($node['item'])) {
            $type = strtolower((string)$node['item']);
        } else {
            $type = str_replace(['_id', 'Id'], '', $key);
            $type = strtolower($type);
        }
        $oldInt = (int)$old_id;
        if (isset($this->id_mapping[$type]) && isset($this->id_mapping[$type][$oldInt])) {
            return (string)$this->id_mapping[$type][$oldInt];
        }
        return (string)$old_id;
    }

    // Prepare conditional logic for saving (serialize if needed)
    protected function prepareConditionalLogic($logic) {
        if (empty($logic)) {
            return '';
        }
        try {
            if (is_array($logic)) {
                return maybe_serialize($logic);
            }
            if (is_string($logic)) {
                // Try to decode if JSON
                $decoded = json_decode($logic, true);
                if (json_last_error() === JSON_ERROR_NONE) {
                    return maybe_serialize($decoded);
                }
                $maybe = maybe_unserialize($logic);
                return is_array($maybe) ? maybe_serialize($maybe) : $logic;
            }
        } catch (\Exception $e) {
            $this->log->add('error', 'conditional_logic', 0, get_current_user_id(), 'Conditional logic parse error: ' . $e->getMessage(), 'data');
            return '';
        }
        return '';
    }


    // Save conditional logic for a newly imported form
    protected function saveConditionalLogic($form_id, $logic) {
        $prepared = $this->prepareConditionalLogic($logic);
        // Update or insert conditional logic with error catching
        try {
            $this->wpdb->update(
                $this->config->getTable('form'),
                ['conditional_logic' => $prepared],
                ['id' => $form_id]
            );
            return true;
        } catch (\Exception $e) {
            $this->log->add('error', 'conditional_logic', $form_id, get_current_user_id(), 'Failed to update conditional logic: ' . $e->getMessage(), 'data');
            return false;
        }
    }

    // Main method to start the import process
    public function importForm($is_template = false) {
        $form_id = $this->insertForm($this->form_data, $is_template);
        if ($form_id) {
            $this->insertPages($form_id, $this->form_data['pages'] ?? []);
            $this->restoreImportedIntegrationSettings($form_id);
            // Save conditional logic if provided with ID remapping
            if (isset($this->form_data['conditional_logic'])) {
                $remapped_logic = $this->remapConditionalLogicIds($this->form_data['conditional_logic']);
                $this->saveConditionalLogic($form_id, $remapped_logic);
            }
            return $form_id;
        } else {
            return false;
        }
    }

    // Insert the form data
    protected function insertForm($form, $is_template) {
        $origin = $is_template ? 'template' : 'imported'; // Check if the form is created from a template
    
        $normalized_user_action = wp_unslash($form['user_action'] ?? []);
        $compliance_mode = isset($form['compliance_mode']) ? absint($form['compliance_mode']) : 0;
        $compliance_profile = sanitize_text_field($form['compliance_profile'] ?? 'standard');
        $flags_raw = $form['compliance_flags'] ?? [];
        $compliance_flags = [];
        if (is_string($flags_raw)) {
            if (is_serialized($flags_raw)) {
                $decoded = $this->maybeDecode($flags_raw);
                $compliance_flags = is_array($decoded) ? $decoded : [];
            } else {
                $decoded = json_decode($flags_raw, true);
                if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                    $compliance_flags = $decoded;
                } else {
                    $decoded = maybe_unserialize($flags_raw);
                    $compliance_flags = is_array($decoded) ? $decoded : [];
                }
            }
        } elseif (is_array($flags_raw)) {
            $compliance_flags = $flags_raw;
        }
    
        $this->wpdb->insert($this->config->getTable('form'), [
            'name'        => sanitize_text_field($form['name'] ?? __('form', 'griffinforms-form-builder')),
            'heading'     => sanitize_text_field($form['heading'] ?? ''),
            'description' => sanitize_text_field($form['description'] ?? ''),
            'folder'      => 0,
            'autofill'    => sanitize_text_field($form['autofill'] ?? ''),
            'limit_entries' => maybe_serialize(wp_unslash($form['limit_entries'] ?? [])),
            'progress_bar' => maybe_serialize(wp_unslash($form['progress_bar'] ?? [])),
            'access_level'  => maybe_serialize(wp_unslash($form['access_level'] ?? [])),
            'submission_edit' => maybe_serialize(wp_unslash($form['submission_edit'] ?? [])),
            'user_action'   => maybe_serialize($normalized_user_action),
            'alert_emails'  => maybe_serialize(wp_unslash($form['alert_emails'] ?? [])),
            'save_entries'  => sanitize_text_field($form['save_entries'] ?? ''),
            'autoresponder' => sanitize_text_field($form['autoresponder'] ?? ''),
            'compliance_mode' => $compliance_mode,
            'compliance_profile' => $compliance_profile,
            'compliance_flags' => !empty($compliance_flags) ? maybe_serialize($compliance_flags) : '',
            'formpages'     => maybe_serialize([]),
            'origin'        => $origin, // Set origin to 'template' or 'imported'
            'author'        => get_current_user_id(),
            'created'       => current_time('mysql', true)
        ]);
    
        return $this->wpdb->insert_id;
    }

    protected function restoreImportedIntegrationSettings($form_id)
    {
        if ($form_id <= 0) {
            return;
        }

        $raw_settings = $this->form_data['integration_settings'] ?? [];
        $decoded_settings = $this->decodeImportedIntegrationSettings($raw_settings);

        if (!is_array($decoded_settings) || empty($decoded_settings)) {
            return;
        }

        $accounts_payload = $decoded_settings['wordpress_accounts'] ?? null;
        if (!is_array($accounts_payload) || empty($accounts_payload)) {
            return;
        }

        $remapped_payload = $this->remapImportedAccountsPayload($accounts_payload);
        $save_result = FormSettingsManager::getInstance()->saveIntegrationSettings($form_id, 'wordpress_accounts', $remapped_payload);

        if (is_wp_error($save_result)) {
            $this->log->add(
                'error',
                'form',
                $form_id,
                get_current_user_id(),
                'Imported Accounts settings could not be restored: ' . $save_result->get_error_message(),
                'import'
            );
            return;
        }

        $this->log->add(
            'info',
            'form',
            $form_id,
            get_current_user_id(),
            'Imported Accounts settings restored with remapped field references.',
            'import'
        );
    }

    protected function decodeImportedIntegrationSettings($raw_settings)
    {
        if (is_array($raw_settings)) {
            return $raw_settings;
        }

        if (!is_string($raw_settings) || $raw_settings === '') {
            return [];
        }

        $decoded = json_decode($raw_settings, true);
        if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
            return $decoded;
        }

        $maybe = $this->maybeDecode($raw_settings);
        return is_array($maybe) ? $maybe : [];
    }

    protected function remapImportedAccountsPayload(array $payload): array
    {
        $rules = $payload['settings']['rules'] ?? [];
        if (!is_array($rules)) {
            $rules = [];
        }

        foreach ($rules as $index => $rule) {
            if (!is_array($rule)) {
                continue;
            }

            $rules[$index] = $this->remapImportedAccountsRule($rule);
        }

        $payload['settings']['rules'] = $rules;
        return $payload;
    }

    protected function remapImportedAccountsRule(array $rule): array
    {
        $field_keys = [
            'email_field_id',
            'password_field_id',
            'first_name_field_id',
            'last_name_field_id',
            'username_field_id',
            'profile_image_field_id',
        ];

        foreach ($field_keys as $key) {
            $rule[$key] = $this->remapImportedFieldReference($rule[$key] ?? 0);
        }

        if (!empty($rule['send_confirmation_email'])) {
            $confirmation_message_id = absint($rule['confirmation_message_id'] ?? 0);
            if ($confirmation_message_id > 0 && !$this->importedConfirmationMessageExists($confirmation_message_id)) {
                $rule['confirmation_message_id'] = 0;
            }
        }

        return $rule;
    }

    protected function remapImportedFieldReference($old_field_id): int
    {
        $old_field_id = absint($old_field_id);
        if ($old_field_id <= 0) {
            return 0;
        }

        return isset($this->id_mapping['field'][$old_field_id])
            ? absint($this->id_mapping['field'][$old_field_id])
            : 0;
    }

    protected function importedConfirmationMessageExists(int $message_id): bool
    {
        $message_id = absint($message_id);
        if ($message_id <= 0) {
            return false;
        }

        $table = $this->config->getTable('message');
        $found = $this->wpdb->get_var(
            $this->wpdb->prepare(
                "SELECT id FROM %i WHERE id = %d",
                $table,
                $message_id
            )
        );

        return absint($found) === $message_id;
    }

    // Insert pages related to the form
    protected function insertPages($form_id, $pages) {
        if (!is_array($pages)) {
            return; // Return early if $pages is not an array
        }
    
        $page_ids = []; // Collect page IDs here
        $table = $this->config->getTable('formpage');
    
        foreach ($pages as $page) {
            $old_page_id = $page['id'] ?? null;
            $this->wpdb->insert($table, [
                'name'        => sanitize_text_field($page['name'] ?? ''),
                'heading'     => sanitize_text_field($page['heading'] ?? ''),
                'description' => sanitize_text_field($page['description'] ?? ''),
                'pagerows'    => maybe_serialize([]), // Rows inserted later
                'step_data'   => maybe_serialize(is_array($page['step_data'] ?? null) ? $page['step_data'] : [
                    'step_name' => '',
                    'step_icon' => '',
                ]),
                'author'      => get_current_user_id(),
                'created'     => current_time('mysql', true)
            ]);
            $page_id = $this->wpdb->insert_id;
    
            // Track ID mapping for pages
            if ($old_page_id) {
                $this->id_mapping['page'][$old_page_id] = $page_id;
            }
    
            // Collect the page ID
            $page_ids[] = $page_id;
    
            // Insert related rows for each page
            $this->insertRows($page_id, $page['rows'] ?? []);
        }
    
        // Now that all pages are inserted, update the formpages field in the form
        $this->wpdb->update($this->config->getTable('form'), [
            'formpages' => maybe_serialize($page_ids) // Serialize the array of page IDs
        ], ['id' => $form_id]);
    }

    // Insert rows related to the page
    protected function insertRows($page_id, $rows) {
        if (!is_array($rows)) {
            return; // Return early if $rows is not an array
        }
    
        $row_ids = []; // Collect row IDs here
        $table = $this->config->getTable('pagerow');

    
        foreach ($rows as $row) {
            $expanded_rows = $this->expandRowByWidth($row);
            $is_first_expansion = true;

            foreach ($expanded_rows as $expanded_row) {
                $old_row_id = $is_first_expansion ? ($row['id'] ?? null) : null;

                $this->wpdb->insert($table, [
                    'name'        => sanitize_text_field($expanded_row['name'] ?? ''),
                    'heading'     => sanitize_text_field($expanded_row['heading'] ?? ''),
                    'description' => sanitize_text_field($expanded_row['description'] ?? ''),
                    'rowcolumns'  => maybe_serialize([]), // Columns inserted later
                    'author'      => get_current_user_id(),
                    'created'     => current_time('mysql', true)
                ]);
                $row_id = $this->wpdb->insert_id;
        
                // Track ID mapping for rows (only for the original row)
                if ($old_row_id) {
                    $this->id_mapping['row'][$old_row_id] = $row_id;
                }
        
                // Collect the row ID
                $row_ids[] = $row_id;
        
                // Insert related columns for each row
                $this->insertColumns($row_id, $expanded_row['columns'] ?? []);

                $is_first_expansion = false;
            }
        }
    
        // Now that all rows are inserted, update the pagerows field in the page
        $this->wpdb->update($this->config->getTable('formpage'), [
            'pagerows' => maybe_serialize($row_ids) // Serialize the array of row IDs
        ], ['id' => $page_id]);
    }

    /**
     * Ensure imported rows don't exceed the 12-column grid by splitting overflow
     * columns into follow-up rows. This avoids UI overflow when templates are malformed.
     *
     * @param array $row
     * @return array<int, array>
     */
    private function expandRowByWidth(array $row): array
    {
        $columns = $row['columns'] ?? [];
        if (!is_array($columns) || count($columns) < 2) {
            return [$row];
        }

        $widths = [];
        foreach ($columns as $column) {
            $widths[] = absint($column['width'] ?? 12);
        }

        if (array_sum($widths) <= 12) {
            return [$row];
        }

        // translators: %1$s is the row heading/title, %2$d is the total width sum.
        $this->log->add(
            'warning',
            'form',
            0,
            get_current_user_id(),
            sprintf(
                __('Template row "%1$s" exceeds grid width (%2$d). Auto-splitting into multiple rows.', 'griffinforms-form-builder'),
                sanitize_text_field($row['heading'] ?? ($row['name'] ?? '')),
                (int) array_sum($widths)
            ),
            'import'
        );

        $out = [];
        $chunk = [];
        $chunk_width = 0;
        $suffix = 0;

        foreach ($columns as $column) {
            $col_width = absint($column['width'] ?? 12);
            if ($chunk && ($chunk_width + $col_width) > 12) {
                $new_row = $row;
                if ($suffix > 0) {
                    $new_row['name'] = ($row['name'] ?? 'Row') . ' (continued)';
                    $new_row['description'] = '';
                }
                $new_row['columns'] = $chunk;
                $new_row['rowcolumns'] = array_map(static function ($c) {
                    return $c['id'] ?? null;
                }, $chunk);
                $new_row['rowcolumns'] = array_values(array_filter($new_row['rowcolumns'], static function ($v) {
                    return $v !== null;
                }));

                $out[] = $new_row;
                $chunk = [];
                $chunk_width = 0;
                $suffix++;
            }

            $chunk[] = $column;
            $chunk_width += $col_width;
        }

        if ($chunk) {
            $new_row = $row;
            if ($suffix > 0) {
                $new_row['name'] = ($row['name'] ?? 'Row') . ' (continued)';
                $new_row['description'] = '';
            }
            $new_row['columns'] = $chunk;
            $new_row['rowcolumns'] = array_map(static function ($c) {
                return $c['id'] ?? null;
            }, $chunk);
            $new_row['rowcolumns'] = array_values(array_filter($new_row['rowcolumns'], static function ($v) {
                return $v !== null;
            }));
            $out[] = $new_row;
        }

        return $out ?: [$row];
    }

    // Insert columns related to the row
    protected function insertColumns($row_id, $columns) {
        if (!is_array($columns)) {
            return; // Return early if $columns is not an array
        }
    
        $column_ids = []; // Collect column IDs here
        $table = $this->config->getTable('rowcolumn');

    
        foreach ($columns as $column) {
            $old_column_id = $column['id'] ?? null;
            $this->wpdb->insert($table, [
                'name'        => sanitize_text_field($column['name'] ?? ''),
                'heading'     => sanitize_text_field($column['heading'] ?? ''),
                'description' => sanitize_text_field($column['description'] ?? ''),
                'fields'      => maybe_serialize([]), // Fields inserted later
                'width'       => absint($column['width'] ?? 12), // Default width set to 12
                'author'      => get_current_user_id(),
                'created'     => current_time('mysql', true)
            ]);
            $column_id = $this->wpdb->insert_id;
    
            // Track ID mapping for columns
            if ($old_column_id) {
                $this->id_mapping['column'][$old_column_id] = $column_id;
            }
    
            // Collect the column ID
            $column_ids[] = $column_id;
    
            // Insert related fields for each column
            $this->insertFields($column_id, $column['field_data'] ?? []);
        }
    
        // Now that all columns are inserted, update the rowcolumns field in the row
        $this->wpdb->update($this->config->getTable('pagerow'), [
            'rowcolumns' => maybe_serialize($column_ids) // Serialize the array of column IDs
        ], ['id' => $row_id]);
    }

    // Insert fields related to the column
    protected function insertFields($column_id, $fields) {
        if (!is_array($fields)) {
            return; // Return early if $fields is not an array
        }
    
        $field_ids = []; // Collect field IDs here
        $table = $this->config->getTable('field');
        foreach ($fields as $field) {
            if (!empty($field)) {
                $field_type = sanitize_key((string) ($field['field_type'] ?? ''));

                // Check if the field type is valid
                if (!$this->config->isPortableFieldType($field_type)) {
                    $this->log->add('error', 'field', 0, get_current_user_id(), 'Unsupported field type: ' . ($field['field_type'] ?? ''), 'data');
                    continue;
                }

                if (!$this->config->isRegisteredFieldType($field_type)) {
                    $this->log->add('warning', 'field', 0, get_current_user_id(), 'Preserving unavailable field type during import: ' . $field_type, 'package_provider');
                }
    
                $old_field_id = $field['id'] ?? null;
                // Insert the field if it's valid
                $this->wpdb->insert($table, [
                    'field_type'    => $field_type,
                    'name'          => sanitize_text_field($field['name'] ?? ''),
                    'heading'       => sanitize_text_field($field['heading'] ?? ''),
                    'description'   => sanitize_text_field($field['description'] ?? ''),
                    'is_required'   => absint($field['is_required'] ?? 0),
                    'is_hidden'     => absint($field['is_hidden'] ?? 0),
                    'field_options' => maybe_serialize(wp_unslash($field['field_options'] ?? [])),
                    'placeholder'   => sanitize_text_field($field['placeholder'] ?? ''),
                    'default_value' => maybe_serialize(wp_unslash($field['default_value'] ?? [])),
                    'is_readonly'   => absint($field['is_readonly'] ?? 0),
                    'is_disabled'   => absint($field['is_disabled'] ?? 0),
                    'autocomplete'  => sanitize_text_field($field['autocomplete'] ?? ''),
                    'iterations'    => maybe_serialize(wp_unslash($field['iterations'] ?? [])),
                    'validations'   => maybe_serialize(wp_unslash($field['validations'] ?? [])),
                    'field_settings'=> maybe_serialize(wp_unslash($field['field_settings'] ?? [])),
                    'is_reusable'   => absint($field['is_reusable'] ?? 0),
                    'author'        => get_current_user_id(),
                    'created'       => current_time('mysql', true)
                ]);
                $field_id = $this->wpdb->insert_id;
    
                // Track ID mapping for fields
                if ($old_field_id) {
                    $this->id_mapping['field'][$old_field_id] = $field_id;
                }
    
                // Collect the field ID
                $field_ids[] = $field_id;
            }
        }
    
        // Now that all fields are inserted, update the fields field in the column
        $this->wpdb->update($this->config->getTable('rowcolumn'), [
            'fields' => maybe_serialize($field_ids) // Correctly store field IDs, not column IDs
        ], ['id' => $column_id]);
    }
}
