<?php

/**
 * JCOGS Image Pro - Border Parameter Package
 * ==========================================
 * Sophisticated form interface for border parameter
 * 
 * @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      Parameter Package Implementation
 */

namespace JCOGSDesign\JCOGSImagePro\Service\ParameterPackages;

/**
 * Border Parameter Package
 * 
 * Provides sophisticated 3-field interface for border parameter instead of requiring
 * users to construct complex pipe-separated parameter strings manually.
 * 
 * Border Parameter Format (from JCOGS documentation):
 * border="<integer>[px|%]|[#]<three or six digit hex colour code>"
 * 
 * Examples:
 * - border="10|4a2d14" - 10px width with color #4a2d14
 * - border="10px|#DDD" - 10px width with color #DDD
 * - border="15px|rgb(220,240,260)" - 15px width with RGB color
 * 
 * Documentation: https://jcogs.net/documentation/jcogs_img/jcogs_img-parameters#jcogs-image-parameter-border
 */
class BorderParameterPackage extends AbstractParameterPackage
{
    /**
     * Package identifier
     * 
     * @return string Package name
     */
    public function getName(): string 
    {
        return 'border_parameter_package';
    }

    /**
     * Get the display label for this parameter package
     * 
     * @return string Package label
     */
    public function getLabel(): string
    {
        return 'Border Parameters';
    }

    /**
     * Get the description for this parameter package
     * 
     * @return string Package description
     */
    public function getDescription(): string
    {
        return 'Border width and color controls for image framing';
    }

    /**
     * Get the category for this parameter package
     * 
     * @return string Package category
     */
    public function getCategory(): string
    {
        return 'transformational';
    }

    /**
     * Parameters handled by this package
     * 
     * @return array List of parameter names
     */
    public function getParameters(): array 
    {
        return ['border'];
    }

    /**
     * Parse composite border string into associative array
     * 
     * Supports three formats with automatic detection:
     * 1. Named attributes (preferred): "border_width:10px|border_color:4a2d14"
     * 2. Legacy positional: "10px|4a2d14"
     * 3. Minimal positional: "10px"
     * 
     * @param string $param_name Parameter name (e.g., 'border')
     * @param string $composite_string Raw parameter value to parse
     * @return array Associative array with border_width, border_color keys
     */
    public function parseCompositeString(string $param_name, string $composite_string): array
    {
        if (empty(trim($composite_string))) {
            return $this->getDefaultValues();
        }

        // Priority 1: Try named attribute format (has colons)
        if (strpos($composite_string, ':') !== false) {
            $parsed = $this->parseNamedAttributes($composite_string);
            if (!empty($parsed)) {
                return array_merge($this->getDefaultValues(), $parsed);
            }
        }

        // Priority 2: Try legacy positional format
        return $this->parsePositionalFormat($composite_string);
    }

    /**
     * Parse named attribute format
     * Format: "border_width:10px|border_color:4a2d14"
     * 
     * @param string $composite_string Named attribute string
     * @return array Parsed values or empty array if invalid format
     */
    private function parseNamedAttributes(string $composite_string): array
    {
        $parsed = [];
        $parts = explode('|', trim($composite_string));

        foreach ($parts as $part) {
            $part = trim($part);
            if (empty($part)) {
                continue;
            }

            if (strpos($part, ':') === false) {
                continue;
            }

            list($name, $value) = explode(':', $part, 2);
            $name = trim($name);
            $value = trim($value);

            // Only accept border_* attributes
            if (strpos($name, 'border_') === 0) {
                $parsed[$name] = $value;
            }
        }

        return $parsed;
    }

    /**
     * Parse legacy positional format
     * Format: "10px|4a2d14" or "10px"
     * 
     * @param string $composite_string Positional format string
     * @return array Associative array with border_width, border_color keys
     */
    private function parsePositionalFormat(string $composite_string): array
    {
        $defaults = $this->getDefaultValues();
        $parts = array_map('trim', explode('|', trim($composite_string)));

        // Treat empty strings as null to use defaults (fixes issue #100 with |||)
        return [
            'border_width' => (!empty($parts[0]) ? $parts[0] : $defaults['border_width']),
            'border_color' => (!empty($parts[1] ?? '') ? $parts[1] : $defaults['border_color'])
        ];
    }

    /**
     * Get default values for all border sub-parameters
     * 
     * @return array Default values
     */
    private function getDefaultValues(): array
    {
        return [
            'border_width' => '',
            'border_color' => '#FFFFFF'
        ];
    }

    /**
     * Normalize border parameter to positional format
     * 
     * Accepts both formats and returns consistent positional pipe-delimited format:
     * - Input (positional): "10px|4a2d14" → Output: "10px|4a2d14"
     * - Input (named): "border_width:10px|border_color:4a2d14" → Output: "10px|4a2d14"
     * 
     * @param string $border_parameter Border parameter string in either format
     * @return string Normalized positional pipe-delimited format
     */
    public function normalizeBorderParameter(string $border_parameter): string
    {
        if (empty($border_parameter)) {
            return '';
        }

        // Convert named format to positional if needed
        if ($this->isNamedAttributeFormat($border_parameter)) {
            return $this->convertNamedToPositionalFormat($border_parameter);
        }

        // Already in positional format
        return $border_parameter;
    }

    /**
     * Get validation definitions for border sub-parameters
     * 
     * This is the SINGLE SOURCE OF TRUTH for border parameter validation rules.
     * All validation (preset forms, CP forms, filter processing) should use these definitions.
     * 
     * Border parameter format: "width|color"
     * Example: "10px|#4a2d14"
     * 
     * @return array Map of sub-parameter names to validation configurations
     */
    public function getSubParameterDefinitions(): array
    {
        return [
            // Sub-parameter 1: Border width
            'border_width' => [
                'label' => 'Border Width',
                'description' => 'Width of the border in pixels or percentage',
                'type' => 'text',
                'default_value' => '',
                'validator' => 'numeric',
                'validation_config' => [
                    'allow_negative' => false,
                    'allow_percentage' => true,
                    'allow_units' => ['px', '%'],
                    'min_value' => 0,
                    'default_unit' => 'px'
                ],
                'required' => true,
                'placeholder' => '10px or 5%'
            ],

            // Sub-parameter 2: Border color
            'border_color' => [
                'label' => 'Border Color',
                'description' => 'Color of the border (hex, rgb, rgba, or named color)',
                'type' => 'text',
                'default_value' => '#FFFFFF',
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\ColourValidator::class,
                'validation_config' => [
                    'allow_empty' => true
                ],
                'required' => false,
                'placeholder' => '#4a2d14, rgb(220,240,260), or white'
            ]
        ];
    }

    /**
     * Get priority for this parameter package
     * Higher numbers = higher priority when multiple packages could handle the same parameter
     * 
     * @return int Priority level (higher = more specific, gets chosen first)
     */
    public function getPriority(): int
    {
        return 24; // Higher than TransformationalParameterPackage (20)
    }

    /**
     * Get form fields for border parameter
     * 
     * @param array $current_values Current parameter values  
     * @return array Flat associative array of form fields
     */
    protected function getPackageFormFields(array $current_values = []): array
    {
        // Get current border value
        $current_value = $current_values['border'] ?? '';
        
        // Parse existing border value using new composite parser (supports named and positional formats)
        $parsed = $this->parseCompositeString('border', $current_value);
        
        return [
            'border_width' => [
                'type' => 'text',
                'label' => $this->lang('jcogs_img_pro_param_border_width_label', 'Border Width'),
                'desc' => $this->lang('jcogs_img_pro_param_border_width_desc', 'Width of the border (e.g., 10, 15px, 5%)'),
                'value' => $parsed['border_width'] ?? '',
                'placeholder' => $this->lang('jcogs_img_pro_param_border_width_placeholder', 'For example: 10px')
            ],
            
            'border_color' => [
                'type' => 'text',
                'label' => $this->lang('jcogs_img_pro_param_border_color_label', 'Border Color'),
                'desc' => $this->lang('jcogs_img_pro_param_border_color_desc', 'Color of the border. Supports hex codes (3, 4, 6, or 8 digit), CSS rgb()/rgba(), or color names. JCOGS automatically adds # prefix if omitted.'),
                'value' => $parsed['border_color'] ?? '',
                'placeholder' => $this->lang('jcogs_img_pro_param_border_color_placeholder', 'For example: 4a2d14, #DDD, rgb(220,240,260), rgba(255,128,0,0.8)'),
                'attrs' => [
                    'class' => 'form-control jcogs-color-field',
                    'data-color-picker' => 'true'
                ]
            ]
        ];
    }

    /**
     * Process form data to generate border parameter value in named attributes format
     * 
     * Generates self-documenting format: "border_width:10px|border_color:4a2d14"
     * 
     * @param string $parameter_name Parameter name (should be 'border')
     * @param array $form_data Form submission data
     * @return string Formatted border parameter value in named attributes format
     */
    public function processParameterFromForm(string $parameter_name, array $form_data): string 
    {
        $parts = [];

        // Border width (required for valid border)
        $width = trim($form_data['border_width'] ?? '');
        if (empty($width)) {
            return ''; // No width means no border to save
        }
        $parts[] = "border_width:{$width}";

        // Border color (optional, but include if provided)
        $color = trim($form_data['border_color'] ?? '');
        if (!empty($color)) {
            // Keep color as-is (including # if present) for named format
            $parts[] = "border_color:{$color}";
        }

        // Return named attributes format
        return implode('|', $parts);
    }

    // NOTE: validateParameter() override removed
    // Now uses AbstractParameterPackage::validateParameter() which automatically
    // validates composite parameters using getSubParameterDefinitions() and ColourValidator

    /**
     * Detect if parameter string uses named attribute format
     * 
     * Named format: "border_width:10px|border_color:#4a2d14"
     * Positional format: "10px|#4a2d14"
     * 
     * @param string $border_parameter Border parameter string
     * @return bool True if named attribute format detected
     */
    private function isNamedAttributeFormat(string $border_parameter): bool
    {
        // Check for named format (both full and alias forms)
        $parts = explode('|', trim($border_parameter));
        
        if (empty($parts)) {
            return false;
        }
        
        // Known attribute names (both full and alias forms)
        $known_names = [
            'border_width', 'width',
            'border_color', 'color'
        ];
        
        // Check first part for known attribute names
        $first_part = trim($parts[0]);
        if (strpos($first_part, ':') !== false) {
            list($name, ) = explode(':', $first_part, 2);
            if (in_array(trim($name), $known_names)) {
                return true;
            }
        }
        
        // Otherwise positional
        return false;
    }

    /**
     * Convert named attribute format to positional pipe-delimited format
     * 
     * @param string $border_parameter Named attribute format string
     * @return string Positional pipe-delimited format string
     */
    private function convertNamedToPositionalFormat(string $border_parameter): string
    {
        // Parse named attributes into associative array
        $named_values = [];
        $parts = explode('|', trim($border_parameter));
        
        foreach ($parts as $part) {
            $part = trim($part);
            if (empty($part)) {
                continue;
            }
            
            // Split on first colon
            if (strpos($part, ':') !== false) {
                list($name, $value) = explode(':', $part, 2);
                $named_values[trim($name)] = trim($value);
            }
        }
        
        // Build positional format
        $positional = [];
        
        // 1. Border width (required) - support both full name and alias
        $width = $named_values['border_width'] ?? $named_values['width'] ?? '';
        if (empty($width)) {
            return ''; // No width means no border
        }
        $positional[] = $width;
        
        // 2. Border color (optional) - support both full name and alias
        $color = $named_values['border_color'] ?? $named_values['color'] ?? '';
        if (!empty($color)) {
            // Remove # prefix if present (normalized format doesn't include it)
            $color = ltrim($color, '#');
            $positional[] = $color;
        }
        
        // Join with pipe
        return implode('|', $positional);
    }
}
