<?php

/**
 * JCOGS Image Pro - Add Parameter Route
 * ======================================
 * Route for adding parameters to presets
 * 
 * @category   ExpressionEngine Add-on
 * @package    JCOGS Image Pro
 * @author     JCOGS Design <contact@jcogs.net>
 * @copyright  Copyright (c) 2021 - 2025 JCOGS Design
 * @license    https://jcogs.net/add-ons/license/jcogs_img_pro
 * @version    2.0.6
 * @link       https://JCOGS.net/
 * @since      Presets Feature Implementation
 */

namespace JCOGSDesign\JCOGSImagePro\ControlPanel\Routes\Presets;

use Exception;
use JCOGSDesign\JCOGSImagePro\ControlPanel\Routes\ImageAbstractRoute;
use JCOGSDesign\JCOGSImagePro\Service\ParameterRegistry;
use JCOGSDesign\JCOGSImagePro\Service\ParameterPackageDiscovery;

class AddParameter extends ImageAbstractRoute
{
    /**
     * @var string Route path for URL generation
     */
    protected $route_path = 'presets/add_parameter';

    /**
     * @var string Control panel page title
     */
    protected $cp_page_title;

    /**
     * Add parameter form processor
     * 
     * @param mixed $preset_id Preset ID to add parameter to (may be unused if extracted from URL)
     * @return $this Fluent interface for EE7 routing
     */
    public function process($preset_id = false)
    {
        // Validate and load preset using shared helper method
        $preset = $this->validateAndLoadPresetFromUrl('add_error');
        if (!$preset) {
            return $this; // Helper method handles error and redirect
        }
        
        // Handle POST request - add the parameter
        if (count($_POST) > 0) {
            return $this->_handle_add_parameter($preset);
        }
        
        // GET request - get parameter from query string
        $parameter_name = (string) (ee()->input->get('parameter') ?: '');
        if ($parameter_name === '') {
            ee('CP/Alert')->makeInline('add_error')
                ->asIssue()
                ->withTitle('Invalid Parameter')
                ->addToBody('No parameter specified.')
                ->defer();
                
            ee()->functions->redirect(ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset_id));
            return $this;
        }

        $parameter_name = ParameterRegistry::resolveParameterAlias($parameter_name);
        
        // Validate parameter name
        $registry = new ParameterRegistry();
        if (!$registry->parameterExists($parameter_name)) {
            ee('CP/Alert')->makeInline('add_error')
                ->asIssue()
                ->withTitle('Invalid Parameter')
                ->addToBody('The specified parameter is not valid.')
                ->defer();
                
            ee()->functions->redirect(ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset_id));
            return $this;
        }
        
        // Check if parameter already exists in preset
        $parameters = ParameterRegistry::normalizeParameterNames($preset['parameters'] ?? []);
        if (isset($parameters[$parameter_name])) {
            ee('CP/Alert')->makeInline('add_error')
                ->asIssue()
                ->withTitle('Parameter Exists')
                ->addToBody('This parameter is already configured for this preset.')
                ->defer();
                
            ee()->functions->redirect(ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset_id));
            return $this;
        }
        
        // Show add form
        $this->cp_page_title = 'Add Parameter: ' . ucfirst(str_replace('_', ' ', $parameter_name));
        $this->build_sidebar($this->getCurrentSettings());
        $this->addBreadcrumb('presets', 'Preset Management', ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets'));
        $this->addBreadcrumb('edit', 'Edit: ' . $preset['name'], ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset_id));
        $this->addBreadcrumb('add_parameter', $this->cp_page_title);

        // Build the add form
        $variables = $this->_build_add_form($preset, $parameter_name);

        // Load CSS assets for the parameter add interface
        $this->_load_parameter_add_assets();

        // Set the page body
        $this->setBody('preset_add_parameter', $variables);

        return $this;
    }

    /**
     * Handle POST request to add parameter
     * 
     * @param array $preset Current preset data
     * @return $this
     */
    private function _handle_add_parameter(array $preset)
    {
        if (! $this->ensureMutationAllowed('add_preset_parameter', 'presets/edit/' . $preset['id'])) {
            return $this;
        }

        $form_data = $_POST;
        $parameter_name = (string) (
            $form_data['parameter']
            ?? $form_data['parameter_name']
            ?? ee()->input->post('parameter')
            ?? ee()->input->post('parameter_name')
            ?? ''
        );
        $parameter_name = ParameterRegistry::resolveParameterAlias($parameter_name);
        $parameter_value = (string) (ee()->input->post('parameter_value') ?: '');
        
        // Basic validation
        if (empty($parameter_name)) {
            ee('CP/Alert')->makeInline('add_error')
                ->asIssue()
                ->withTitle('Validation Error')
                ->addToBody('Parameter name is required.')
                ->defer();
                
            ee()->functions->redirect(ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset['id']));
            return $this;
        }
        
        try {
            $registry = new ParameterRegistry();
            $discovery = new ParameterPackageDiscovery($registry);
            $target_package = $this->_get_package_for_parameter($parameter_name, $registry, $discovery);

            if ($target_package) {
                $parameter_value = $target_package->processParameterFromForm($parameter_name, $form_data);
            }

            // **Task 21: Validate parameter value before saving**
            $validation_result = $this->_validate_parameter_value($parameter_name, $parameter_value);
            if ($validation_result !== true) {
                throw new Exception($validation_result);
            }
            
            // Get current parameters
            $parameters = ParameterRegistry::normalizeParameterNames($preset['parameters'] ?? []);

            if (isset($parameters[$parameter_name])) {
                throw new Exception('This parameter is already configured for this preset.');
            }
            
            // Add the new parameter
            $parameters[$parameter_name] = $parameter_value;
            
            // Update the preset
            $result = $this->preset_service->updatePreset($preset['name'], [
                'parameters' => $parameters
            ]);
            
            if ($result['success']) {
                ee('CP/Alert')->makeInline('add_success')
                    ->asSuccess()
                    ->withTitle('Parameter Added')
                    ->addToBody('Parameter "' . htmlspecialchars($parameter_name) . '" has been added successfully.')
                    ->defer();
            } else {
                throw new Exception($result['error'] ?? 'Unknown error occurred');
            }
            
        } catch (Exception $e) {
            $this->utilities_service->debug_log('parameter_add_error', $e->getMessage());
            
            ee('CP/Alert')->makeInline('add_error')
                ->asIssue()
                ->withTitle('Add Failed')
                ->addToBody('Failed to add parameter: ' . $e->getMessage())
                ->defer();
        }
        
        // Redirect back to edit page
        ee()->functions->redirect(ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset['id']));
        return $this;
    }

    /**
     * Build add parameter form
     * 
     * @param array $preset Current preset data
     * @param string $parameter_name Parameter to add
     * @return array Template variables
     */
    private function _build_add_form(array $preset, string $parameter_name): array
    {
        $form = ee('CP/Form');
        
        // Set form action URL
        $form_action_url = ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/add_parameter/' . $preset['id']);
        $form->setBaseUrl($form_action_url);
        
        // Configure form buttons
        $form->set('save_btn_text', 'Add Parameter');
        $form->set('save_btn_text_working', 'Adding');
        
        // Get parameter category and package information
        $registry = new ParameterRegistry();
        $category = $registry->getParameterCategory($parameter_name);
        
        // Create group for Parameter Details
        $details_group = $form->getGroup('Parameter Details');
        
        // Parameter name fieldset
        $name_fieldset = $details_group->getFieldSet('Parameter Name');
        $name_fieldset->setDesc('Parameter: ' . $parameter_name . ' (Category: ' . ucfirst($category) . ')');
        $name_fieldset->getField('parameter', 'hidden')
            ->setValue($parameter_name);
        $name_fieldset->getField('parameter_name', 'hidden')
            ->setValue($parameter_name);
        $readonly_field = $name_fieldset->getField('parameter_name_display', 'text')
            ->setValue($parameter_name);
        $readonly_field->set('attrs', 'readonly="readonly" class="form-control readonly-field"');
        
        // Use parameter package for sophisticated form field generation
        try {
            $discovery = new ParameterPackageDiscovery($registry);
            $target_package = $this->_get_package_for_parameter($parameter_name, $registry, $discovery);

            if ($target_package) {
                    // Generate sophisticated form fields using parameter package
                    $current_values = []; // No current value for new parameter
                    $package_fields = $target_package->generateFormFields($current_values);

                    $parameter_fields = [];
                    foreach ($package_fields as $field_name => $field_config) {
                        if ($field_name === $parameter_name || strpos($field_name, $parameter_name . '_') === 0) {
                            $parameter_fields[$field_name] = $field_config;
                        }
                    }

                    // Some packages (for example srcset) expose package-level keys rather than
                    // parameter-name-prefixed keys. In that case, include all generated fields.
                    if (empty($parameter_fields) && !empty($package_fields)) {
                        $parameter_fields = $package_fields;
                    }

                    if (!empty($parameter_fields)) {
                        $hidden_fields = [];
                        $visible_fields = [];

                        foreach ($parameter_fields as $field_name => $field_config) {
                            if (($field_config['type'] ?? 'text') === 'hidden') {
                                $hidden_fields[$field_name] = $field_config;
                            } else {
                                $visible_fields[$field_name] = $field_config;
                            }
                        }

                        foreach ($hidden_fields as $field_name => $field_config) {
                            $hidden_field = $form->getHiddenField($field_name);
                            $hidden_field->setValue($field_config['value'] ?? '');
                        }

                        if (!empty($visible_fields)) {
                            if (count($visible_fields) > 1) {
                                foreach ($visible_fields as $field_name => $field_config) {
                                    $field_key = str_replace($parameter_name . '_', '', $field_name);
                                    $field_title = $field_config['label'] ?? ucfirst(str_replace('_', ' ', $field_key));
                                    $component_fieldset = $details_group->getFieldSet($field_title);

                                    $description = $field_config['desc'] ?? '';
                                    if (is_array($description)) {
                                        $description = implode(' ', $description);
                                    }
                                    $component_fieldset->setDesc($description);

                                    if (isset($field_config['example'])) {
                                        $component_fieldset->setExample('For example: ' . $field_config['example']);
                                    }

                                    $field_type = $field_config['type'] ?? 'text';

                                    if ($field_type === 'html') {
                                        $html_content = $field_config['content'] ?? '';
                                        $field = $component_fieldset->getField($field_name, 'html');
                                        if (method_exists($field, 'setContent')) {
                                            $field->setContent($html_content);
                                        } else {
                                            $field->setValue($html_content);
                                        }
                                    } else {
                                        $field = $component_fieldset->getField($field_name, $field_type);
                                        $field->setValue($field_config['value'] ?? '');
                                    }

                                    if (isset($field_config['attrs'])) {
                                        $attrs_string = '';
                                        foreach ($field_config['attrs'] as $attr => $attr_value) {
                                            $attrs_string .= $attr . '="' . htmlspecialchars($attr_value) . '" ';
                                        }
                                        if (!empty($attrs_string)) {
                                            $field->set('attrs', trim($attrs_string));
                                        }
                                    }

                                    if (in_array(($field_config['type'] ?? ''), ['select', 'radio'], true) && isset($field_config['choices'])) {
                                        $field->setChoices($field_config['choices']);
                                    }

                                    if (isset($field_config['required']) && $field_config['required']) {
                                        $field->setRequired(true);
                                    }

                                    if (isset($field_config['note'])) {
                                        $field->setNote($field_config['note']);
                                    }
                                }
                            } else {
                                $field_name = (string) array_key_first($visible_fields);
                                $field_config = reset($visible_fields);
                                $value_fieldset = $details_group->getFieldSet('Parameter Value');
                                $value_fieldset->setDesc($field_config['desc'] ?? 'Configure the value for this parameter');

                                $field_type = $field_config['type'] ?? 'text';
                                if ($field_type === 'html') {
                                    $field = $value_fieldset->getField($field_name, 'html');
                                    $html_content = $field_config['content'] ?? '';
                                    if (method_exists($field, 'setContent')) {
                                        $field->setContent($html_content);
                                    } else {
                                        $field->setValue($html_content);
                                    }
                                } else {
                                    $field = $value_fieldset->getField($field_name, $field_type);
                                    $field->setValue($field_config['value'] ?? '');
                                }

                                if (in_array(($field_config['type'] ?? ''), ['select', 'radio'], true) && isset($field_config['choices'])) {
                                    $field->setChoices($field_config['choices']);
                                }
                            }
                        }
                    } else {
                        // Fallback to basic text field if parameter not found in package
                        $this->_add_fallback_field($details_group, $parameter_name);
                    }
            } else {
                // Fallback to basic text field if no package handles this parameter
                $this->_add_fallback_field($details_group, $parameter_name);
            }
        } catch (Exception $e) {
            // Fallback to basic text field on any errors
            $this->_add_fallback_field($details_group, $parameter_name);
            
            // Log the error for debugging
            ee('jcogs_img_pro:Logging')->error('AddParameter package integration error: ' . $e->getMessage(), [
                'parameter_name' => $parameter_name,
                'category' => $category,
                'preset_id' => $preset['id']
            ]);
        }
        
        return [
            'cp_page_title' => $this->cp_page_title,
            'form' => $form,
            'preset' => $preset,
            'parameter_name' => $parameter_name,
            'cancel_url' => ee('CP/URL')->make('addons/settings/jcogs_img_pro/presets/edit/' . $preset['id'])
        ];
    }
    
    /**
     * Add fallback text field when parameter packages are unavailable
     * 
     * @param mixed $details_group Form group instance
     * @param string $parameter_name Parameter name
     * @return void
     */
    private function _add_fallback_field($details_group, string $parameter_name): void
    {
        $value_fieldset = $details_group->getFieldSet('Parameter Value');
        $value_fieldset->setDesc('Enter the value for this parameter (same format as used in tags)');
        $fallback_field = $value_fieldset->getField('parameter_value', 'text')
            ->setValue('');
        $fallback_field->set('attrs', 'class="form-control" placeholder="Enter parameter value..."');
    }

    /**
     * Load CSS assets for the parameter add interface
     * 
     * @return void
     */
    private function _load_parameter_add_assets(): void
    {
        // Add parameter add CSS file using EE's recommended method
        ee()->cp->add_to_head('<link rel="stylesheet" type="text/css" href="' . URL_THIRD_THEMES . 'jcogs_img_pro/css/parameter-add.css">');
    }

    /**
     * Validate parameter value before saving
     * 
     * Uses ParameterPackageDiscovery to validate the parameter value
     * including composite parameter sub-value validation (Task 21).
     * 
     * @param string $parameter_name Parameter name
     * @param mixed $parameter_value Parameter value to validate
     * @return bool|string True if valid, error message if invalid
     */
    private function _validate_parameter_value(string $parameter_name, $parameter_value)
    {
        try {
            // Load the parameter package discovery service
            $packageDiscovery = new ParameterPackageDiscovery();
            
            // Validate the specific parameter
            $validation_errors = $packageDiscovery->validateAllParameters([
                $parameter_name => $parameter_value
            ]);
            
            // Check if there are validation errors for this parameter
            if (!empty($validation_errors) && isset($validation_errors[$parameter_name])) {
                return $validation_errors[$parameter_name];
            }
            
            return true;
            
        } catch (Exception $e) {
            // If validation service fails, allow the update (graceful degradation)
            return true;
        }
    }

    /**
     * Get the parameter package for a specific parameter.
     *
     * @param string $parameter_name
     * @param ParameterRegistry|null $registry
     * @param ParameterPackageDiscovery|null $discovery
     * @return mixed|null
     */
    private function _get_package_for_parameter(
        string $parameter_name,
        ?ParameterRegistry $registry = null,
        ?ParameterPackageDiscovery $discovery = null
    ) {
        try {
            if ($registry === null) {
                $registry = new ParameterRegistry();
            }
            if ($discovery === null) {
                $discovery = new ParameterPackageDiscovery($registry);
            }

            $direct_package = $discovery->getPackageForParameter($parameter_name);
            if ($direct_package) {
                return $direct_package;
            }

            $packages = $discovery->getPackages();
            foreach ($packages as $package) {
                if (in_array($parameter_name, $package->getParameters(), true)) {
                    return $package;
                }
            }
        } catch (Exception $e) {
            return null;
        }

        return null;
    }
}

