<?php

/**
 * JCOGS Image Pro - Text Parameter Package
 * ========================================
 * Sophisticated multi-field interface for text overlay parameters
 * 
 * @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;

use JCOGSDesign\JCOGSImagePro\Service\ParameterPackages\AbstractParameterPackage;
use JCOGSDesign\JCOGSImagePro\Service\ParameterRegistry;

/**
 * Text Parameter Package
 * 
 * Provides sophisticated multi-field interface for complex text overlay parameters.
 * The text parameter supports 16 pipe-separated sub-parameters for complete text overlay control.
 * 
 * Text Parameter Format (pipe-separated):
 * 1. the_text (required) - Text content to overlay
 * 2. minimum_dimensions - min_width,min_height for text addition
 * 3. font_size - Size in pixels or points (add 'pt' suffix)
 * 4. line_height - Line spacing (pixels, points, or percentage)
 * 5. font_color - Text color (hex, rgb, rgba)
 * 6. font_src - Path to TTF font file relative to web root
 * 7. text_align - left|center|right alignment
 * 8. width_adjustment - Text box width constraint
 * 9. position - horizontal,vertical position (left|center|right, top|center|bottom)
 * 10. offset - horizontal,vertical offset from position
 * 11. opacity - Text opacity (0-100)
 * 12. shadow_color - Shadow color (hex, rgb, rgba)
 * 13. shadow_offset - Shadow horizontal,vertical offset
 * 14. shadow_opacity - Shadow opacity (0-100)
 * 15. text_box_bg_color - Background color for text box
 * 16. text_bg_color - Background color for text
 * 17. rotation - Text rotation in degrees (anti-clockwise)
 */
class TextParameterPackage extends AbstractParameterPackage
{
    /**
     * Package identifier
     * 
     * @return string Package name
     */
    public function getName(): string 
    {
        return 'text_parameter_package';
    }

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

    /**
     * Get the description for this parameter package
     * 
     * @return string Package description
     */
    public function getDescription(): string
    {
        return 'Sophisticated text overlay parameters with comprehensive typography and positioning controls';
    }

    /**
     * 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 ['text'];
    }

    /**
     * Normalize text parameter to positional format
     * 
     * Accepts both formats and returns consistent positional pipe-delimited format:
     * - Input (positional): "value|0,0|20px|..." → Output: "value|0,0|20px|..."
     * - Input (named): "text_content:value|text_font_size:20px|..." → Output: "value|0,0|20px|..."
     * 
     * This method is the bridge between template tags and the TextOverlay filter,
     * ensuring backward compatibility while supporting the new named attribute system.
     * 
     * @param string $text_parameter Text parameter string in either format
     * @return string Normalized positional pipe-delimited format
     */
    public function normalizeTextParameter(string $text_parameter): string
    {
        if (empty($text_parameter)) {
            return '';
        }

        // Convert named format to positional if needed
        if ($this->isNamedAttributeFormat($text_parameter)) {
            $converted = $this->convertNamedToPositionalFormat($text_parameter);
            ee('jcogs_img:Utilities')->debug_message('text_parameter_converted', [
                'input' => $text_parameter,
                'output' => $converted
            ]);
            return $converted;
        }

        // Already in positional format
        return $text_parameter;
    }

    /**
     * Get validation definitions for text sub-parameters
     * 
     * This is the SINGLE SOURCE OF TRUTH for text parameter validation rules.
     * All validation (preset forms, CP forms, filter processing) should use these definitions.
     * 
     * @return array Map of sub-parameter names to validation configurations
     */
    public function getSubParameterDefinitions(): array
    {
        return [
            'text_content' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\StringValidator::class,
                'config' => [
                    'min_length' => 1,
                    'max_length' => 1000,
                    'allow_empty' => false
                ],
                'required' => true,
                'default' => '',
                'label' => 'Text Content',
                'desc' => 'The text to overlay on the image'
            ],
            
            'text_min_width' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => 0,
                    'max' => 10000,
                    'allow_decimal' => false,
                    'allow_percentage' => true,
                    'allow_units' => ['px']
                ],
                'required' => false,
                'default' => '0',
                'label' => 'Minimum Image Width',
                'desc' => 'Minimum width the image must have for text to be added'
            ],
            
            'text_min_height' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => 0,
                    'max' => 10000,
                    'allow_decimal' => false,
                    'allow_percentage' => true,
                    'allow_units' => ['px']
                ],
                'required' => false,
                'default' => '0',
                'label' => 'Minimum Image Height',
                'desc' => 'Minimum height the image must have for text to be added'
            ],
            
            'text_font_size' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => 4,
                    'max' => 500,
                    'allow_decimal' => true,
                    'allow_units' => ['px', 'pt']
                ],
                'required' => false,
                'default' => '12px',
                'label' => 'Font Size',
                'desc' => 'Font size in pixels (px) or points (pt)'
            ],
            
            'text_line_height' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => 0.5,
                    'max' => 10.0,
                    'allow_decimal' => true,
                    'allow_percentage' => true,
                    'allow_units' => ['px', 'pt']
                ],
                'required' => false,
                'default' => '1.25',
                'label' => 'Line Height',
                'desc' => 'Line spacing multiplier, pixel value, or percentage'
            ],
            
            'text_font_color' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\ColourValidator::class,
                'config' => [
                    'allow_empty' => false
                ],
                'required' => false,
                'default' => '#FFFFFF',
                'label' => 'Text Color',
                'desc' => 'Text color in hex, rgb(), rgba(), or CSS color name (e.g., darkred, navy)'
            ],
            
            'text_font_src' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\StringValidator::class,
                'config' => [
                    'max_length' => 500,
                    'allow_empty' => true
                ],
                'required' => false,
                'default' => '',
                'label' => 'Font Path',
                'desc' => 'Path to TTF font file relative to web root'
            ],
            
            'text_align' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\EnumValidator::class,
                'config' => [
                    'allowed_values' => ['left', 'center', 'right'],
                    'case_sensitive' => false
                ],
                'required' => false,
                'default' => 'center',
                'label' => 'Text Alignment',
                'desc' => 'Text alignment within text box'
            ],
            
            'text_width_adjustment' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => -100,
                    'max' => 10000,
                    'allow_decimal' => true,
                    'allow_negative' => true,
                    'allow_percentage' => true,
                    'allow_units' => ['px']
                ],
                'required' => false,
                'default' => '',
                'label' => 'Text Box Width',
                'desc' => 'Width constraint for text box (positive = width, negative = reduction from image width)'
            ],
            
            'text_position_horizontal' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\EnumValidator::class,
                'config' => [
                    'allowed_values' => ['left', 'center', 'right'],
                    'case_sensitive' => false
                ],
                'required' => false,
                'default' => 'center',
                'label' => 'Horizontal Position',
                'desc' => 'Horizontal position of text box on image'
            ],
            
            'text_position_vertical' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\EnumValidator::class,
                'config' => [
                    'allowed_values' => ['top', 'center', 'bottom'],
                    'case_sensitive' => false
                ],
                'required' => false,
                'default' => 'center',
                'label' => 'Vertical Position',
                'desc' => 'Vertical position of text box on image'
            ],
            
            'text_offset_horizontal' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => -5000,
                    'max' => 5000,
                    'allow_decimal' => true,
                    'allow_negative' => true,
                    'allow_percentage' => true,
                    'allow_units' => ['px']
                ],
                'required' => false,
                'default' => '0',
                'label' => 'Horizontal Offset',
                'desc' => 'Fine-tune horizontal position with pixel or percentage offset'
            ],
            
            'text_offset_vertical' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => -5000,
                    'max' => 5000,
                    'allow_decimal' => true,
                    'allow_negative' => true,
                    'allow_percentage' => true,
                    'allow_units' => ['px']
                ],
                'required' => false,
                'default' => '0',
                'label' => 'Vertical Offset',
                'desc' => 'Fine-tune vertical position with pixel or percentage offset'
            ],
            
            'text_opacity' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\PercentageValidator::class,
                'config' => [
                    'min' => 0,
                    'max' => 100,
                    'allow_decimal' => true,
                    'format' => 'percent' // 0-100 format
                ],
                'required' => false,
                'default' => '100',
                'label' => 'Text Opacity',
                'desc' => 'Text opacity (0-100)'
            ],
            
            'text_shadow_color' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\ColourValidator::class,
                'config' => [
                    'allow_empty' => true
                ],
                'required' => false,
                'default' => '',
                'label' => 'Shadow Color',
                'desc' => 'Shadow color in hex, rgb(), rgba(), or CSS color name'
            ],
            
            'text_shadow_offset_h' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => -100,
                    'max' => 100,
                    'allow_decimal' => true,
                    'allow_negative' => true
                ],
                'required' => false,
                'default' => '1',
                'label' => 'Shadow Horizontal Offset',
                'desc' => 'Shadow horizontal offset in pixels'
            ],
            
            'text_shadow_offset_v' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => -100,
                    'max' => 100,
                    'allow_decimal' => true,
                    'allow_negative' => true
                ],
                'required' => false,
                'default' => '1',
                'label' => 'Shadow Vertical Offset',
                'desc' => 'Shadow vertical offset in pixels'
            ],
            
            'text_shadow_opacity' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\PercentageValidator::class,
                'config' => [
                    'min' => 0,
                    'max' => 100,
                    'allow_decimal' => true,
                    'format' => 'percent' // 0-100 format
                ],
                'required' => false,
                'default' => '100',
                'label' => 'Shadow Opacity',
                'desc' => 'Shadow opacity (0-100)'
            ],
            
            'text_box_bg_color' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\ColourValidator::class,
                'config' => [
                    'allow_empty' => true
                ],
                'required' => false,
                'default' => '',
                'label' => 'Text Box Background Color',
                'desc' => 'Background color for text box container (hex, rgb, rgba, or CSS name)'
            ],
            
            'text_bg_color' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\ColourValidator::class,
                'config' => [
                    'allow_empty' => true
                ],
                'required' => false,
                'default' => '',
                'label' => 'Text Background Color',
                'desc' => 'Background color behind each character (hex, rgb, rgba, or CSS name)'
            ],
            
            'text_rotation' => [
                'validator' => \JCOGSDesign\JCOGSImagePro\Service\Validation\NumericValidator::class,
                'config' => [
                    'min' => -360,
                    'max' => 360,
                    'allow_decimal' => true,
                    'allow_negative' => true
                ],
                'required' => false,
                'default' => '0',
                'label' => 'Text Rotation',
                'desc' => 'Rotation angle in degrees (anti-clockwise)'
            ]
        ];
    }

    /**
     * Priority for text parameter package
     * Higher priority than general transformational package
     * 
     * @return int Priority order (lower numbers = higher priority)
     */
    public function getPriority(): int
    {
        return 25;  // Higher priority than TransformationalParameterPackage (30)
    }

    /**
     * Generate form fields for text parameter
     * 
     * @param array $current_values Current parameter values
     * @return array Field configuration array
     */
    protected function getPackageFormFields(array $current_values = []): array 
    {
        // Parse current text parameter value
        $text_components = $this->parseTextParameter($current_values['text'] ?? '');
        
        return [
            // Enable/disable toggle
            'text_enabled' => [
                'type' => 'hidden',
                'value' => !empty($text_components['the_text']) ? 'yes' : 'no',
                'label' => 'Text Overlay Enabled'
            ],
            
            // Core text content
            'text_content' => [
                'type' => 'textarea',
                'value' => $text_components['the_text'] ?? '',
                'label' => 'Text Content',
                'desc' => 'The text to overlay on the image. Line breaks are supported.',
                'example' => 'Copyright 2025 • All Rights Reserved',
                'required' => true
            ],
            
            // Minimum dimensions for text addition
            'text_min_width' => [
                'type' => 'text',
                'value' => $text_components['min_width'] ?? '0',
                'label' => 'Minimum Image Width',
                'desc' => 'Minimum width the image must have for text to be added (pixels or %).',
                'example' => '100px or 50%'
            ],
            
            'text_min_height' => [
                'type' => 'text',
                'value' => $text_components['min_height'] ?? '0',
                'label' => 'Minimum Image Height',
                'desc' => 'Minimum height the image must have for text to be added (pixels or %).',
                'example' => '100px or 50%'
            ],
            
            // Typography settings
            'text_font_size' => [
                'type' => 'text',
                'value' => $text_components['font_size'] ?? '12px',
                'label' => 'Font Size',
                'desc' => 'Font size in pixels (px) or points (pt). Default: 12px.',
                'example' => '16px or 14pt'
            ],
            
            'text_line_height' => [
                'type' => 'text',
                'value' => $text_components['line_height'] ?? '1.25',
                'label' => 'Line Height',
                'desc' => 'Line spacing multiplier or pixel value. Default: 1.25 (125%).',
                'example' => '1.5 or 18px or 120%'
            ],
            
            'text_font_color' => [
                'type' => 'text',
                'value' => $text_components['font_color'] ?? '#FFFFFF',
                'label' => 'Text Color',
                'desc' => 'Text color in hex, rgb(), or rgba() format. Default: white.',
                'example' => '#FF0000 or rgb(255,0,0) or rgba(255,0,0,0.8)',
                'attrs' => [
                    'class' => 'form-control jcogs-color-field',
                    'data-color-picker' => 'true'
                ]
            ],
            
            'text_font_src' => [
                'type' => 'text',
                'value' => $text_components['font_src'] ?? '',
                'label' => 'Font Path',
                'desc' => 'Relative path from webroot to font file (e.g., fonts/arial.ttf). Leave empty to use default Voces Regular.',
                'placeholder' => 'fonts/your-font.ttf'
            ],
            
            'text_align' => [
                'type' => 'select',
                'value' => $text_components['text_align'] ?? 'center',
                'label' => 'Text Alignment',
                'desc' => 'How text is aligned within the text box.',
                'choices' => [
                    'left' => 'Left aligned',
                    'center' => 'Center aligned',
                    'right' => 'Right aligned'
                ]
            ],
            
            // Layout and positioning
            'text_width_adjustment' => [
                'type' => 'text',
                'value' => $text_components['width_adjustment'] ?? '',
                'label' => 'Text Box Width',
                'desc' => 'Width constraint for text box. Positive = width, negative = reduction from image width.',
                'example' => '40% or -20% or 300px'
            ],
            
            'text_position_horizontal' => [
                'type' => 'select',
                'value' => $text_components['position_horizontal'] ?? 'center',
                'label' => 'Horizontal Position',
                'desc' => 'Horizontal position of text box on image.',
                'choices' => [
                    'left' => 'Left edge',
                    'center' => 'Center',
                    'right' => 'Right edge'
                ]
            ],
            
            'text_position_vertical' => [
                'type' => 'select',
                'value' => $text_components['position_vertical'] ?? 'center',
                'label' => 'Vertical Position',
                'desc' => 'Vertical position of text box on image.',
                'choices' => [
                    'top' => 'Top edge',
                    'center' => 'Center',
                    'bottom' => 'Bottom edge'
                ]
            ],
            
            'text_offset_horizontal' => [
                'type' => 'text',
                'value' => $text_components['offset_horizontal'] ?? '0',
                'label' => 'Horizontal Offset',
                'desc' => 'Fine-tune horizontal position with pixel or percentage offset.',
                'example' => '10px or -5% or 0'
            ],
            
            'text_offset_vertical' => [
                'type' => 'text',
                'value' => $text_components['offset_vertical'] ?? '0',
                'label' => 'Vertical Offset',
                'desc' => 'Fine-tune vertical position with pixel or percentage offset.',
                'example' => '10px or -5% or 0'
            ],
            
            // Visual effects
            'text_opacity' => [
                'type' => 'text',
                'value' => $text_components['opacity'] ?? '100',
                'label' => 'Text Opacity',
                'desc' => 'Text opacity from 0 (transparent) to 100 (opaque). Default: 100.',
                'example' => '80'
            ],
            
            'text_shadow_color' => [
                'type' => 'text',
                'value' => $text_components['shadow_color'] ?? '',
                'label' => 'Shadow Color',
                'desc' => 'Color for text shadow. Leave empty for no shadow.',
                'example' => '#000000 or rgba(0,0,0,0.5)',
                'attrs' => [
                    'class' => 'form-control jcogs-color-field',
                    'data-color-picker' => 'true'
                ]
            ],
            
            'text_shadow_offset_horizontal' => [
                'type' => 'text',
                'value' => $text_components['shadow_offset_horizontal'] ?? '1',
                'label' => 'Shadow Horizontal Offset',
                'desc' => 'Horizontal shadow offset in pixels.',
                'example' => '2'
            ],
            
            'text_shadow_offset_vertical' => [
                'type' => 'text',
                'value' => $text_components['shadow_offset_vertical'] ?? '1',
                'label' => 'Shadow Vertical Offset',
                'desc' => 'Vertical shadow offset in pixels.',
                'example' => '2'
            ],
            
            'text_shadow_opacity' => [
                'type' => 'text',
                'value' => $text_components['shadow_opacity'] ?? '100',
                'label' => 'Shadow Opacity',
                'desc' => 'Shadow opacity from 0 (transparent) to 100 (opaque).',
                'example' => '60'
            ],
            
            // Background colors
            'text_box_bg_color' => [
                'type' => 'text',
                'value' => $text_components['text_box_bg_color'] ?? '',
                'label' => 'Text Box Background',
                'desc' => 'Background color for the entire text box area. Leave empty for transparent.',
                'example' => 'rgba(0,0,0,0.3)',
                'attrs' => [
                    'class' => 'form-control jcogs-color-field',
                    'data-color-picker' => 'true'
                ]
            ],
            
            'text_bg_color' => [
                'type' => 'text',
                'value' => $text_components['text_bg_color'] ?? '',
                'label' => 'Text Background',
                'desc' => 'Background color behind the text characters. Leave empty for transparent.',
                'example' => 'rgba(255,255,255,0.8)',
                'attrs' => [
                    'class' => 'form-control jcogs-color-field',
                    'data-color-picker' => 'true'
                ]
            ],
            
            // Rotation
            'text_rotation' => [
                'type' => 'text',
                'value' => $text_components['rotation'] ?? '0',
                'label' => 'Text Rotation',
                'desc' => 'Rotation angle in degrees (anti-clockwise). Default: 0 (no rotation).',
                'example' => '45 or -30'
            ]
        ];
    }

    /**
     * Process form data and build text parameter string
     * 
     * @param string $parameter_name Parameter being processed
     * @param array $form_data Form submission data
     * @return string Processed parameter value
     */
    public function processParameterFromForm(string $parameter_name, array $form_data): string 
    {
        if ($parameter_name !== 'text') {
            return '';
        }

        // Check if text is enabled
        if (empty($form_data['text_content'])) {
            return '';
        }

        // Build named attributes format for presets (self-documenting, order-independent)
        // Format: text_content:value|text_font_size:16px|text_line_height:1.5
        $components = [];
        
        // Map form fields to named attributes (only include non-empty values)
        $field_mapping = [
            'text_content' => $form_data['text_content'] ?? '',
            'text_min_width' => $form_data['text_min_width'] ?? '0',
            'text_min_height' => $form_data['text_min_height'] ?? '0',
            'text_font_size' => $form_data['text_font_size'] ?? '12px',
            'text_line_height' => $form_data['text_line_height'] ?? '1.25',
            'text_font_color' => $form_data['text_font_color'] ?? '#FFFFFF',
            'text_font_src' => $form_data['text_font_src'] ?? '',
            'text_align' => $form_data['text_align'] ?? 'center',
            'text_width_adjustment' => $form_data['text_width_adjustment'] ?? '',
            'text_position_horizontal' => $form_data['text_position_horizontal'] ?? 'center',
            'text_position_vertical' => $form_data['text_position_vertical'] ?? 'center',
            'text_offset_horizontal' => $form_data['text_offset_horizontal'] ?? '0',
            'text_offset_vertical' => $form_data['text_offset_vertical'] ?? '0',
            'text_opacity' => $form_data['text_opacity'] ?? '100',
            'text_shadow_color' => $form_data['text_shadow_color'] ?? '',
            'text_shadow_offset_h' => $form_data['text_shadow_offset_horizontal'] ?? $form_data['text_shadow_offset_h'] ?? '1',
            'text_shadow_offset_v' => $form_data['text_shadow_offset_vertical'] ?? $form_data['text_shadow_offset_v'] ?? '1',
            'text_shadow_opacity' => $form_data['text_shadow_opacity'] ?? '100',
            'text_box_bg_color' => $form_data['text_box_bg_color'] ?? '',
            'text_bg_color' => $form_data['text_bg_color'] ?? '',
            'text_rotation' => $form_data['text_rotation'] ?? '0'
        ];

        // Generate named attributes (include all fields for consistency)
        foreach ($field_mapping as $field_name => $value) {
            $components[] = $field_name . ':' . $value;
        }

        // Join with pipe separator
        $parameter_string = implode('|', $components);
        
        // Remove trailing empty components
        $parameter_string = rtrim($parameter_string, '|');
        
        return $parameter_string;
    }

    /**
     * Detect if parameter string uses named attribute format
     * 
     * Named format: "text_content:value|text_font_size:20px|..."
     * Positional format: "value|0,0|20px|..."
     * 
     * @param string $text_parameter Text parameter string
     * @return bool True if named attribute format detected
     */
    private function isNamedAttributeFormat(string $text_parameter): bool
    {
        // Named format has colon separators in pipe-delimited parts
        // Check first few parts for "name:value" pattern
        $parts = explode('|', trim($text_parameter));
        
        if (empty($parts)) {
            return false;
        }
        
        // Known attribute names (both full and alias forms)
        $known_names = [
            'text_content', 'content',
            'text_min_width', 'text_min_height', 'min_size',
            'text_font_size', 'font_size',
            'text_line_height', 'line_height',
            'text_font_color', 'color', 'font_color',
            'text_font_src', 'font', 'font_src',
            'text_align', 'align',
            'text_width_adjustment', 'box_width', 'width_adjustment',
            'text_position_horizontal', 'text_position_vertical', 'position',
            'text_offset_horizontal', 'text_offset_vertical', 'offset',
            'text_opacity', 'opacity',
            'text_shadow_color', 'shadow_color',
            'text_shadow_offset', 'shadow_offset', 'text_shadow_offset_h', 'text_shadow_offset_v',
            'text_shadow_opacity', 'shadow_opacity',
            'text_box_bg_color', 'box_bg', 'text_box_bg',
            'text_bg_color', 'text_bg',
            'text_rotation', 'rotation'
        ];
        
        // Check first 3 parts for named format indicators
        $named_count = 0;
        $check_limit = min(3, count($parts));
        
        for ($i = 0; $i < $check_limit; $i++) {
            $part = trim($parts[$i]);
            if (strpos($part, ':') !== false) {
                list($name, ) = explode(':', $part, 2);
                if (in_array(trim($name), $known_names)) {
                    $named_count++;
                }
            }
        }
        
        // If 2 or more of first 3 parts match named format, assume named
        return $named_count >= 2;
    }

    /**
     * Convert named attribute format to positional pipe-delimited format
     * 
     * @param string $text_parameter Named attribute format string
     * @return string Positional pipe-delimited format string
     */
    private function convertNamedToPositionalFormat(string $text_parameter): string
    {
        // Define alias mappings for shorter attribute names
        $aliases = [
            'content' => 'text_content',
            'min_size' => 'text_min_width', // Will be split later
            'font_size' => 'text_font_size',
            'line_height' => 'text_line_height',
            'color' => 'text_font_color',
            'font_color' => 'text_font_color',
            'font' => 'text_font_src',
            'font_src' => 'text_font_src',
            'align' => 'text_align',
            'text_align' => 'text_align',
            'box_width' => 'text_width_adjustment',
            'width_adjustment' => 'text_width_adjustment',
            'position' => 'text_position', // Will be split into h,v later
            'offset' => 'text_offset', // Will be split into h,v later
            'opacity' => 'text_opacity',
            'shadow_color' => 'text_shadow_color',
            'shadow_offset' => 'text_shadow_offset', // Will be split later
            'shadow_opacity' => 'text_shadow_opacity',
            'box_bg' => 'text_box_bg_color',
            'text_box_bg' => 'text_box_bg_color',
            'text_bg' => 'text_bg_color',
            'rotation' => 'text_rotation',
        ];
        
        // Parse named attributes into associative array
        $named_values = [];
        $parts = explode('|', trim($text_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);
                $name = trim($name);
                $value = trim($value);
                
                // Map alias to full name if needed
                if (isset($aliases[$name])) {
                    $name = $aliases[$name];
                }
                
                $named_values[$name] = $value;
            }
        }
        
        // Handle compound values that need splitting
        // Position: "right,bottom" -> text_position_horizontal and text_position_vertical
        if (isset($named_values['text_position']) && strpos($named_values['text_position'], ',') !== false) {
            list($h, $v) = explode(',', $named_values['text_position'], 2);
            $named_values['text_position_horizontal'] = trim($h);
            $named_values['text_position_vertical'] = trim($v);
        }
        
        // Offset: "-10,-10" -> text_offset_horizontal and text_offset_vertical  
        if (isset($named_values['text_offset']) && strpos($named_values['text_offset'], ',') !== false) {
            list($h, $v) = explode(',', $named_values['text_offset'], 2);
            $named_values['text_offset_horizontal'] = trim($h);
            $named_values['text_offset_vertical'] = trim($v);
        }
        
        // Shadow offset: "1,1" -> text_shadow_offset_h and text_shadow_offset_v
        if (isset($named_values['text_shadow_offset']) && strpos($named_values['text_shadow_offset'], ',') !== false) {
            list($h, $v) = explode(',', $named_values['text_shadow_offset'], 2);
            $named_values['text_shadow_offset_h'] = trim($h);
            $named_values['text_shadow_offset_v'] = trim($v);
        }
        
        // Min size: "100,50" -> text_min_width and text_min_height
        if (isset($named_values['text_min_width']) && strpos($named_values['text_min_width'], ',') !== false) {
            list($w, $h) = explode(',', $named_values['text_min_width'], 2);
            $named_values['text_min_width'] = trim($w);
            $named_values['text_min_height'] = trim($h);
        }
        
        // Build positional format using defined order
        $positional = [];
        
        // 1. Text content (required)
        $positional[] = $named_values['text_content'] ?? '';
        
        // 2. Minimum dimensions (min_width,min_height)
        $min_width = $named_values['text_min_width'] ?? '0';
        $min_height = $named_values['text_min_height'] ?? '0';
        $positional[] = $min_width . ',' . $min_height;
        
        // 3. Font size
        $positional[] = $named_values['text_font_size'] ?? '12px';
        
        // 4. Line height
        $positional[] = $named_values['text_line_height'] ?? '1.25';
        
        // 5. Font color
        $positional[] = $named_values['text_font_color'] ?? '#FFFFFF';
        
        // 6. Font source
        $positional[] = $named_values['text_font_src'] ?? '';
        
        // 7. Text alignment
        $positional[] = $named_values['text_align'] ?? 'center';
        
        // 8. Width adjustment
        $positional[] = $named_values['text_width_adjustment'] ?? '';
        
        // 9. Position (horizontal,vertical)
        $pos_h = $named_values['text_position_horizontal'] ?? 'center';
        $pos_v = $named_values['text_position_vertical'] ?? 'center';
        $positional[] = $pos_h . ',' . $pos_v;
        
        // 10. Offset (horizontal,vertical)
        $offset_h = $named_values['text_offset_horizontal'] ?? '0';
        $offset_v = $named_values['text_offset_vertical'] ?? '0';
        $positional[] = $offset_h . ',' . $offset_v;
        
        // 11. Opacity
        $positional[] = $named_values['text_opacity'] ?? '100';
        
        // 12. Shadow color
        $positional[] = $named_values['text_shadow_color'] ?? '';
        
        // 13. Shadow offset (horizontal,vertical)
        $shadow_h = $named_values['text_shadow_offset_h'] ?? '1';
        $shadow_v = $named_values['text_shadow_offset_v'] ?? '1';
        $positional[] = $shadow_h . ',' . $shadow_v;
        
        // 14. Shadow opacity
        $positional[] = $named_values['text_shadow_opacity'] ?? '100';
        
        // 15. Text box background color
        $positional[] = $named_values['text_box_bg_color'] ?? '';
        
        // 16. Text background color
        $positional[] = $named_values['text_bg_color'] ?? '';
        
        // 17. Rotation
        $positional[] = $named_values['text_rotation'] ?? '0';
        
        // Join with pipe and trim trailing empty values
        return rtrim(implode('|', $positional), '|');
    }

    /**
     * Parse existing text parameter into components
     * 
     * Supports both formats:
     * - Positional: "value|0,0|20px|125%|..."
     * - Named: "text_content:value|text_font_size:20px|..."
     * 
     * @param string $text_parameter Text parameter string
     * @return array Parsed components
     */
    private function parseTextParameter(string $text_parameter): array 
    {
        if (empty($text_parameter)) {
            return [];
        }

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

        $parts = explode('|', $text_parameter);
        $components = [];

        // 1. Text content - treat empty string as empty (fixes issue #100 with |||)
        $components['the_text'] = (!empty($parts[0]) ? $parts[0] : '');
        
        // 2. Minimum dimensions - treat empty string as null
        if (isset($parts[1]) && trim($parts[1]) !== '') {
            $min_dims = explode(',', $parts[1]);
            $components['min_width'] = (!empty($min_dims[0]) ? $min_dims[0] : '0');
            $components['min_height'] = (!empty($min_dims[1] ?? '') ? $min_dims[1] : '0');
        }
        
        // 3-17. Other components - treat empty strings as null to use defaults
        $components['font_size'] = (!empty($parts[2] ?? '') ? $parts[2] : '12px');
        $components['line_height'] = (!empty($parts[3] ?? '') ? $parts[3] : '1.25');
        $components['font_color'] = (!empty($parts[4] ?? '') ? $parts[4] : '#FFFFFF');
        $components['font_src'] = $parts[5] ?? '';
        $components['text_align'] = (!empty($parts[6] ?? '') ? $parts[6] : 'center');
        $components['width_adjustment'] = $parts[7] ?? '';
        
        // Position - treat empty string as null
        if (isset($parts[8]) && trim($parts[8]) !== '') {
            $position = explode(',', $parts[8]);
            $components['position_horizontal'] = (!empty($position[0]) ? $position[0] : 'center');
            $components['position_vertical'] = (!empty($position[1] ?? '') ? $position[1] : 'center');
        }
        
        // Offset - treat empty string as null
        if (isset($parts[9]) && trim($parts[9]) !== '') {
            $offset = explode(',', $parts[9]);
            $components['offset_horizontal'] = (!empty($offset[0]) ? $offset[0] : '0');
            $components['offset_vertical'] = (!empty($offset[1] ?? '') ? $offset[1] : '0');
        }
        
        $components['opacity'] = (!empty($parts[10] ?? '') ? $parts[10] : '100');
        $components['shadow_color'] = $parts[11] ?? '';
        
        // Shadow offset - treat empty string as null
        if (isset($parts[12]) && trim($parts[12]) !== '') {
            $shadow_offset = explode(',', $parts[12]);
            $components['shadow_offset_horizontal'] = (!empty($shadow_offset[0]) ? $shadow_offset[0] : '1');
            $components['shadow_offset_vertical'] = (!empty($shadow_offset[1] ?? '') ? $shadow_offset[1] : '1');
        }
        
        $components['shadow_opacity'] = $parts[13] ?? '100';
        $components['text_box_bg_color'] = $parts[14] ?? '';
        $components['text_bg_color'] = $parts[15] ?? '';
        $components['rotation'] = $parts[16] ?? '0';

        return $components;
    }

    /**
     * Validate text parameter value
     * 
     * @param string $param_name Parameter name being validated
     * @param string $value Parameter value to validate
     * @return bool|string True if valid, error message if invalid
     */
    // NOTE: validateParameter() override REMOVED
    // Now uses AbstractParameterPackage::validateParameter() which provides
    // composite parameter validation using getSubParameterDefinitions().
    // This ensures ALL 21 text sub-parameters are validated, not just the
    // 6 legacy positional checks that were here before.
    
    /**
     * Parse text composite string with backward compatibility
     * 
     * Handles three formats with priority: Named > Legacy > Positional
     * 
     * 1. Named attributes (preferred for presets):
     *    "text_content:Hello|text_font_size:16px|text_line_height:1.5|text_color:#fff"
     * 
     * 2. Legacy 17-value format (backward compatibility for tags):
     *    "text|0,0|12px|1.25|#fff|font.ttf|center||center,center|0,0|100||1,1|100|||0"
     * 
     * 3. Positional 21-value format (fallback):
     *    "text|0|0|12px|1.25|#fff|font.ttf|center||center|center|0|0|100||1|1|100|||0"
     * 
     * @param string $param_name Parameter name (should be 'text')
     * @param string $param_value Parameter value string
     * @return array Associative array of sub-parameter names to values
     */
    public function parseCompositeString(string $param_name, string $param_value): array
    {
        if ($param_name !== 'text' || trim($param_value) === '') {
            return parent::parseCompositeString($param_name, $param_value);
        }

        // Check for named attributes format (contains colons)
        if (strpos($param_value, ':') !== false) {
            return $this->parseNamedAttributes($param_value);
        }

        // Split by pipe for positional formats
        $values = explode('|', $param_value);
        $value_count = count($values);

        // Detect legacy format based on value count and presence of compound values
        $is_legacy_format = false;
        if ($value_count < 21) {
            // Likely legacy format - check for compound values at expected positions
            // Position 1: min dimensions (0,0)
            // Position 8: position (center,center)
            // Position 9: offset (0,0)
            // Position 12: shadow offset (1,1)
            $is_legacy_format = (
                (isset($values[1]) && strpos($values[1], ',') !== false) ||
                (isset($values[8]) && strpos($values[8], ',') !== false) ||
                (isset($values[9]) && strpos($values[9], ',') !== false) ||
                (isset($values[12]) && strpos($values[12], ',') !== false)
            );
        }

        if ($is_legacy_format) {
            // Convert legacy 17-value format to 21-value format
            // Treat empty strings as null to use defaults (fixes issue #100 with |||)
            $expanded = [];
            
            // 0: text_content
            $expanded[0] = $values[0] ?? '';
            
            // 1: Split "0,0" → text_min_width, text_min_height
            if (isset($values[1]) && trim($values[1]) !== '') {
                $min_dims = explode(',', $values[1]);
                $expanded[1] = (!empty($min_dims[0]) ? $min_dims[0] : '0');
                $expanded[2] = (!empty($min_dims[1] ?? '') ? $min_dims[1] : '0');
            } else {
                $expanded[1] = '0';
                $expanded[2] = '0';
            }
            
            // 2-7: Direct mappings (font_size, line_height, color, src, align, width_adj)
            $expanded[3] = (!empty($values[2] ?? '') ? $values[2] : '12px');
            $expanded[4] = (!empty($values[3] ?? '') ? $values[3] : '1.25');
            $expanded[5] = (!empty($values[4] ?? '') ? $values[4] : '#FFFFFF');
            $expanded[6] = $values[5] ?? '';
            $expanded[7] = (!empty($values[6] ?? '') ? $values[6] : 'center');
            $expanded[8] = $values[7] ?? '';
            
            // 8: Split "center,center" → text_position_horizontal, text_position_vertical
            if (isset($values[8]) && trim($values[8]) !== '') {
                $position = explode(',', $values[8]);
                $expanded[9] = (!empty($position[0]) ? $position[0] : 'center');
                $expanded[10] = (!empty($position[1] ?? '') ? $position[1] : 'center');
            } else {
                $expanded[9] = 'center';
                $expanded[10] = 'center';
            }
            
            // 9: Split "0,0" → text_offset_horizontal, text_offset_vertical
            if (isset($values[9]) && trim($values[9]) !== '') {
                $offset = explode(',', $values[9]);
                $expanded[11] = (!empty($offset[0]) ? $offset[0] : '0');
                $expanded[12] = (!empty($offset[1] ?? '') ? $offset[1] : '0');
            } else {
                $expanded[11] = '0';
                $expanded[12] = '0';
            }
            
            // 10-11: Direct mappings (opacity, shadow_color)
            $expanded[13] = (!empty($values[10] ?? '') ? $values[10] : '100');
            $expanded[14] = $values[11] ?? '';
            
            // 12: Split "1,1" → text_shadow_offset_h, text_shadow_offset_v
            if (isset($values[12]) && trim($values[12]) !== '') {
                $shadow_offset = explode(',', $values[12]);
                $expanded[15] = (!empty($shadow_offset[0]) ? $shadow_offset[0] : '1');
                $expanded[16] = (!empty($shadow_offset[1] ?? '') ? $shadow_offset[1] : '1');
            } else {
                $expanded[15] = '1';
                $expanded[16] = '1';
            }
            
            // 13-16: Direct mappings (shadow_opacity, box_bg, text_bg, rotation)
            $expanded[17] = (!empty($values[13] ?? '') ? $values[13] : '100');
            $expanded[18] = $values[14] ?? '';
            $expanded[19] = $values[15] ?? '';
            $expanded[20] = (!empty($values[16] ?? '') ? $values[16] : '0');
            
            // Use expanded values
            $values = $expanded;
        }

        // Map positional values to sub-parameter names
        $sub_params = $this->getSubParameterDefinitions();
        $sub_param_names = array_keys($sub_params);
        
        $parsed = [];
        foreach ($sub_param_names as $index => $sub_param_name) {
            if (isset($values[$index]) && trim($values[$index]) !== '') {
                $parsed[$sub_param_name] = trim($values[$index]);
            } elseif (isset($sub_params[$sub_param_name]['default'])) {
                $parsed[$sub_param_name] = $sub_params[$sub_param_name]['default'];
            } else {
                $parsed[$sub_param_name] = '';
            }
        }

        return $parsed;
    }

    /**
     * Parse named attributes format
     * 
     * Format: text_content:Hello|text_font_size:16px|text_line_height:1.5
     * 
     * @param string $param_value Parameter value string with named attributes
     * @return array Associative array of sub-parameter names to values
     */
    private function parseNamedAttributes(string $param_value): array
    {
        $sub_params = $this->getSubParameterDefinitions();
        $parsed = [];
        
        // Initialize with defaults
        foreach ($sub_params as $name => $definition) {
            $parsed[$name] = $definition['default'] ?? '';
        }
        
        // Split by pipe to get individual attributes
        $attributes = explode('|', $param_value);
        
        foreach ($attributes as $attribute) {
            $attribute = trim($attribute);
            if (empty($attribute)) {
                continue;
            }
            
            // Split by colon to get name:value
            $parts = explode(':', $attribute, 2);
            if (count($parts) !== 2) {
                continue; // Skip malformed attributes
            }
            
            $name = trim($parts[0]);
            $value = trim($parts[1]);
            
            // Only accept known sub-parameter names
            if (isset($sub_params[$name])) {
                $parsed[$name] = $value;
            }
        }
        
        return $parsed;
    }
}
