<?php
/**
 * Field Importer Class
 *
 * Handles importing/pasting of ACF field definitions
 *
 * @package CSCF_ACF
 */

// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}

/**
 * ACF_Copy_Addon_Field_Importer Class
 */
class CSCF_ACF_Field_Importer
{

    /**
     * Decode field data from transfer format
     *
     * @param string $encoded_data Base64 encoded JSON string
     * @return array|false Field array or false on error
     */
    public function decode_field_data($encoded_data)
    {
        // Decode base64
        $json = base64_decode($encoded_data, true);

        if ($json === false) {
            return false;
        }

        // Decode JSON
        $field_data = json_decode($json, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            return false;
        }

        return $field_data;
    }

    /**
     * Validate field data structure
     *
     * @param array $field_data Decoded field array
     * @return bool|WP_Error True if valid, WP_Error if invalid
     */
    public function validate_field_data($field_data)
    {
        // Check if it's an array
        if (!is_array($field_data)) {
            return new WP_Error('invalid_data', __('Field data must be an array', 'cross-site-copy-field-for-acf'));
        }

        // Check required keys - removed 'name' to match ACF default behavior
        // ACF allows fields without names, they will auto-generate one
        $required_keys = array('type', 'label');

        foreach ($required_keys as $key) {
            if (!isset($field_data[$key]) || empty($field_data[$key])) {
                return new WP_Error(
                    'missing_required_key',
                    sprintf(
                        /* translators: %s: Field key name (e.g., 'type', 'name', 'label') */
                        __('Missing required field key: %s', 'cross-site-copy-field-for-acf'),
                        $key
                    )
                );
            }
        }

        return true;
    }

    /**
     * Normalize field data for insertion
     *
     * @param array  $field           Field data array
     * @param string $group_key       Target field group key
     * @param string $parent_field_key Optional parent field key (for nested fields)
     * @return array Normalized field data
     */
    public function normalize_field($field, $group_key, $parent_field_key = '')
    {
        // CRITICAL: Remove ID to prevent overwriting the source field!
        // acf_update_field() will UPDATE if ID exists, we want to CREATE a new field
        unset($field['ID']);
        unset($field['id']);

        // Generate new field key
        $field['key'] = $this->generate_field_key();

        // Set parent to field group OR parent field (for nested fields)
        // If parent_field_key is provided, this is a nested field
        if ($parent_field_key) {
            $field['parent'] = $parent_field_key;
        } else {
            $field['parent'] = $group_key;
            // If pasting to top-level (not inside a flexible content layout),
            // remove parent_layout as it would cause the field to appear incorrectly
            unset($field['parent_layout']);
        }

        // Handle name collision  
        $field['name'] = $this->resolve_name_collision($field['name'], $group_key, $parent_field_key);

        // Recursively normalize sub-fields
        if ($this->has_sub_fields($field)) {
            $field = $this->normalize_sub_fields($field);
        }

        return $field;
    }

    /**
     * Generate unique field key
     *
     * @return string Unique field key
     */
    private function generate_field_key()
    {
        return 'field_' . uniqid();
    }

    /**
     * Check if field has sub-fields
     *
     * @param array $field Field array
     * @return bool
     */
    private function has_sub_fields($field)
    {
        $nested_types = array('repeater', 'group', 'flexible_content', 'clone');
        return in_array($field['type'], $nested_types, true);
    }

    /**
     * Normalize sub-fields recursively
     *
     * @param array $field Parent field array
     * @return array Field with normalized sub-fields
     */
    private function normalize_sub_fields($field)
    {
        switch ($field['type']) {
            case 'repeater':
            case 'group':
                if (!empty($field['sub_fields']) && is_array($field['sub_fields'])) {
                    foreach ($field['sub_fields'] as $index => $sub_field) {
                        // CRITICAL: Remove ID to prevent overwriting existing sub-fields
                        unset($field['sub_fields'][$index]['ID']);
                        unset($field['sub_fields'][$index]['id']);

                        // Generate new key for sub-field
                        $field['sub_fields'][$index]['key'] = $this->generate_field_key();
                        $field['sub_fields'][$index]['parent'] = $field['key'];

                        // Recursively handle nested sub-fields
                        if ($this->has_sub_fields($sub_field)) {
                            $field['sub_fields'][$index] = $this->normalize_sub_fields($field['sub_fields'][$index]);
                        }
                    }
                }
                break;

            case 'flexible_content':
                if (!empty($field['layouts']) && is_array($field['layouts'])) {
                    // Re-index layouts to numeric array (ACF expects this)
                    $normalized_layouts = array();

                    foreach ($field['layouts'] as $layout_index => $layout) {
                        // Generate new layout key
                        $layout['key'] = $this->generate_field_key();

                        if (!empty($layout['sub_fields']) && is_array($layout['sub_fields'])) {
                            foreach ($layout['sub_fields'] as $field_index => $sub_field) {
                                // Remove ID to prevent overwriting
                                unset($layout['sub_fields'][$field_index]['ID']);
                                unset($layout['sub_fields'][$field_index]['id']);

                                $layout['sub_fields'][$field_index]['key'] =
                                    $this->generate_field_key();
                                $layout['sub_fields'][$field_index]['parent'] =
                                    $layout['key'];

                                // Recursively handle nested fields
                                if ($this->has_sub_fields($sub_field)) {
                                    $layout['sub_fields'][$field_index] =
                                        $this->normalize_sub_fields($layout['sub_fields'][$field_index]);
                                }
                            }
                        }

                        // Add to numeric array
                        $normalized_layouts[] = $layout;
                    }

                    // Replace associative array with numeric array
                    $field['layouts'] = $normalized_layouts;
                }
                break;
        }

        return $field;
    }

    /**
     * Resolve field name collision
     *
     * @param string $name            Field name
     * @param string $group_key        Field group key
     * @param string $parent_field_key Optional parent field key (for nested fields)
     * @return string Unique field name
     */
    private function resolve_name_collision($name, $group_key, $parent_field_key = '')
    {
        // Get field group
        $field_group = acf_get_field_group($group_key);

        if (!$field_group) {
            return $name;
        }

        // Get all fields in the group
        $existing_fields = acf_get_fields($group_key);

        if (!$existing_fields) {
            return $name; // No collision possible
        }

        // Extract existing field names
        $existing_names = wp_list_pluck($existing_fields, 'name');

        // Check if name exists
        if (!in_array($name, $existing_names, true)) {
            return $name; // No collision, preserve original name
        }

        // Name collision detected - add suffix
        $base_name = $name;
        $suffix = '_copy';
        $counter = 2;

        // Try _copy first
        if (!in_array($base_name . $suffix, $existing_names, true)) {
            return $base_name . $suffix;
        }

        // Try _copy_2, _copy_3, etc.
        while (in_array($base_name . $suffix . '_' . $counter, $existing_names, true)) {
            $counter++;
        }

        return $base_name . $suffix . '_' . $counter;
    }

    /**
     * Insert field into field group after a specific field
     *
     * @param string $group_key       Field group key
     * @param string $after_field_key Field key to insert after (empty for end)
     * @param array  $new_field       New field data
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function insert_field_after($group_key, $after_field_key, $new_field)
    {
        // Get field group
        $field_group = acf_get_field_group($group_key);

        if (!$field_group) {
            return new WP_Error('group_not_found', __('Field group not found', 'cross-site-copy-field-for-acf'));
        }

        // Set parent
        $new_field['parent'] = $group_key;

        // Calculate menu order (insert after the specified field)
        if (!empty($after_field_key)) {
            $after_field = acf_get_field($after_field_key);
            if ($after_field && isset($after_field['menu_order'])) {
                $new_field['menu_order'] = $after_field['menu_order'] + 1;
            } else {
                $new_field['menu_order'] = 0;
            }
        } else {
            // If no after_field specified, add at the end
            $existing_fields = acf_get_fields($group_key);
            $new_field['menu_order'] = $existing_fields ? count($existing_fields) : 0;
        }

        // Simply add the field - ACF will handle the rest
        $result = acf_update_field($new_field);

        if (!$result) {
            return new WP_Error('field_insert_failed', __('Failed to insert field', 'cross-site-copy-field-for-acf'));
        }

        return true;
    }

    /**
     * Save field group with updated fields
     *
     * @param string $group_key Field group key
     * @param array  $fields    Array of field arrays
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    private function save_field_group_fields($group_key, $fields)
    {
        // Just add/update each field - don't delete existing ones!
        foreach ($fields as $order => $field) {
            $field['parent'] = $group_key;
            $field['menu_order'] = $order;

            $result = acf_update_field($field);

            if (!$result) {
                return new WP_Error('field_update_failed', __('Failed to update field', 'cross-site-copy-field-for-acf'));
            }
        }

        return true;
    }

    /**
     * Import a single field to a field group or parent field
     *
     * @param array  $field           Field data array
     * @param string $group_key       Field group key to add field to
     * @param string $parent_field_key Optional parent field key (for nested fields)
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function import_to_group($field, $group_key, $parent_field_key = '')
    {
        // Verify the field group exists
        $field_group = acf_get_field_group($group_key);

        if (!$field_group) {
            return new WP_Error('invalid_group', __('Field group not found', 'cross-site-copy-field-for-acf'));
        }

        // Set parent to the group OR parent field (for nested fields)
        // CRITICAL: For nested fields, parent should already be set in normalize_field
        // But we override here to ensure we use the correct parent
        if ($parent_field_key) {
            // Nested field - parent should be the parent field's POST ID
            // ACF uses the post ID, not the field key, for parent relationships
            $parent_field = acf_get_field($parent_field_key);
            if ($parent_field && isset($parent_field['ID'])) {
                $field['parent'] = $parent_field['ID'];
            } else {
                // Fallback: try using key directly (might be a layout key)
                $field['parent'] = $parent_field_key;
            }
        } else {
            // Top-level field - parent is the field group ID
            $field['parent'] = $field_group['ID'];
        }

        // Save field and all nested sub-fields recursively
        $this->save_field_recursive($field);

        // Clear caches
        wp_cache_delete($group_key, 'acf');
        wp_cache_delete($field_group['ID'], 'acf');

        if (isset($field_group['ID'])) {
            wp_cache_delete('acf_get_field_group_' . $group_key, 'acf');
            wp_cache_delete('acf_get_field_group_' . $field_group['ID'], 'acf');
        }

        // Nuclear option - flush all caches
        wp_cache_flush();

        return true;
    }

    /**
     * Recursively save a field and all its nested sub-fields
     *
     * @param array $field Field data
     * @return array|WP_Error Saved field data or error
     */
    private function save_field_recursive($field, $depth = 0)
    {
        // Prevent infinite recursion (max 10 levels)
        if ($depth > 10) {
            return new WP_Error('max_depth', __('Maximum nesting depth exceeded', 'cross-site-copy-field-for-acf'));
        }

        // For flexible_content: extract layout sub-fields to save manually
        // For repeater/group, extract sub_fields to save manually
        $sub_fields = array();
        $layout_sub_fields = array(); // For flexible content layouts
        $is_flexible = ($field['type'] === 'flexible_content');

        // Extract layout sub-fields for flexible content BEFORE saving
        if ($is_flexible && isset($field['layouts']) && is_array($field['layouts'])) {
            foreach ($field['layouts'] as $layout) {
                if (!empty($layout['sub_fields']) && is_array($layout['sub_fields'])) {
                    $layout_sub_fields[$layout['key']] = $layout['sub_fields'];
                }
            }
        }

        if (!$is_flexible && isset($field['sub_fields']) && is_array($field['sub_fields'])) {
            // Only for repeater/group: extract sub_fields
            $sub_fields = $field['sub_fields'];
            unset($field['sub_fields']);
        }

        // Save the field
        // - For flexible_content: layouts array is saved, but ACF strips sub_fields from layouts
        // - For repeater/group: sub_fields removed, saved separately below
        $result = acf_update_field($field);

        if (is_wp_error($result)) {
            return $result;
        }

        // For repeater/group: manually save sub-fields
        if (!empty($sub_fields) && !$is_flexible) {
            foreach ($sub_fields as $sub_field) {
                $sub_field['parent'] = $field['key'];
                $this->save_field_recursive($sub_field, $depth + 1);
            }
        }

        // For flexible_content: manually save layout sub-fields
        // ACF stores sub-fields with:
        //   parent = flexible content field's POST ID
        //   parent_layout = layout KEY
        if (!empty($layout_sub_fields) && isset($result['ID'])) {
            $flex_field_id = $result['ID']; // The saved flexible content field's post ID

            foreach ($layout_sub_fields as $layout_key => $fields) {
                foreach ($fields as $sub_field) {
                    // Set parent to the flexible content field's POST ID
                    $sub_field['parent'] = $flex_field_id;
                    // Set parent_layout to the layout key
                    $sub_field['parent_layout'] = $layout_key;

                    $this->save_field_recursive($sub_field, $depth + 1);
                }
            }
        }

        return $result;
    }
}
