<?php

declare(strict_types=1);

namespace App\Framework\Console;

/**
 * Value object containing comprehensive command help information
 */
final readonly class CommandHelp
{
    public function __construct(
        public string $name,
        public string $description,
        public string $usage,
        public array $parameters,
        public array $examples,
        public string $className,
        public string $methodName,
        public array $aliases = []
    ) {
    }

    /**
     * Format help as plain text
     */
    public function formatAsText(): string
    {
        $output = [];

        // Header
        $output[] = "Command: {$this->name}";
        if (! empty($this->aliases)) {
            $output[] = "Aliases: " . implode(', ', $this->aliases);
        }
        $output[] = str_repeat('=', 60);

        // Description
        if (! empty($this->description)) {
            $output[] = "";
            $output[] = "DESCRIPTION:";
            $output[] = $this->wrapText($this->description, 2);
        }

        // Usage
        $output[] = "";
        $output[] = "USAGE:";
        $output[] = "  {$this->usage}";

        // Parameters
        if (! empty($this->parameters)) {
            $output[] = "";
            $output[] = "PARAMETERS:";

            foreach ($this->parameters as $param) {
                $paramLine = "  {$param['name']}";

                // Add type info
                $type = $param['type']['name'];
                if (isset($param['type']['nullable']) && $param['type']['nullable']) {
                    $type .= '?';
                }
                $paramLine .= " ({$type})";

                // Add required/optional indicator
                $paramLine .= $param['required'] ? " *required*" : " [optional]";

                $output[] = $paramLine;

                // Add description
                if (! empty($param['description'])) {
                    $output[] = "    " . $param['description'];
                }

                // Add default value
                if ($param['default'] !== null) {
                    $defaultValue = is_bool($param['default'])
                        ? ($param['default'] ? 'true' : 'false')
                        : $param['default'];
                    $output[] = "    Default: {$defaultValue}";
                }

                // Add validation rules
                if (! empty($param['validation_rules'])) {
                    $rules = [];
                    foreach ($param['validation_rules'] as $rule => $value) {
                        if ($rule === 'required') {
                            continue;
                        }
                        $rules[] = "{$rule}: {$value}";
                    }
                    if (! empty($rules)) {
                        $output[] = "    Validation: " . implode(', ', $rules);
                    }
                }

                $output[] = "";
            }
        }

        // Examples
        if (! empty($this->examples)) {
            $output[] = "EXAMPLES:";
            foreach ($this->examples as $i => $example) {
                $output[] = "  " . ($i + 1) . ". {$example['description']}";
                $output[] = "     {$example['command']}";
                $output[] = "";
            }
        }

        // Technical info
        $output[] = "TECHNICAL INFO:";
        $output[] = "  Class: {$this->className}";
        $output[] = "  Method: {$this->methodName}";

        return implode("\n", $output);
    }

    /**
     * Format help as colored console output
     */
    public function formatAsColoredText(): array
    {
        $sections = [];

        // Header
        $sections[] = [
            'text' => "Command: {$this->name}",
            'color' => 'BRIGHT_CYAN',
        ];

        if (! empty($this->aliases)) {
            $sections[] = [
                'text' => "Aliases: " . implode(', ', $this->aliases),
                'color' => 'GRAY',
            ];
        }

        $sections[] = [
            'text' => str_repeat('=', 60),
            'color' => 'GRAY',
        ];

        // Description
        if (! empty($this->description)) {
            $sections[] = ['text' => "", 'color' => 'WHITE'];
            $sections[] = [
                'text' => "DESCRIPTION:",
                'color' => 'BRIGHT_YELLOW',
            ];
            $sections[] = [
                'text' => $this->wrapText($this->description, 2),
                'color' => 'WHITE',
            ];
        }

        // Usage
        $sections[] = ['text' => "", 'color' => 'WHITE'];
        $sections[] = [
            'text' => "USAGE:",
            'color' => 'BRIGHT_YELLOW',
        ];
        $sections[] = [
            'text' => "  {$this->usage}",
            'color' => 'BRIGHT_WHITE',
        ];

        // Parameters
        if (! empty($this->parameters)) {
            $sections[] = ['text' => "", 'color' => 'WHITE'];
            $sections[] = [
                'text' => "PARAMETERS:",
                'color' => 'BRIGHT_YELLOW',
            ];

            foreach ($this->parameters as $param) {
                $paramText = "  {$param['name']}";

                // Add type info
                $type = $param['type']['name'];
                if (isset($param['type']['nullable']) && $param['type']['nullable']) {
                    $type .= '?';
                }
                $paramText .= " ({$type})";

                // Add required/optional indicator
                if ($param['required']) {
                    $sections[] = [
                        'text' => $paramText . " *required*",
                        'color' => 'BRIGHT_WHITE',
                    ];
                } else {
                    $sections[] = [
                        'text' => $paramText . " [optional]",
                        'color' => 'WHITE',
                    ];
                }

                // Add description
                if (! empty($param['description'])) {
                    $sections[] = [
                        'text' => "    " . $param['description'],
                        'color' => 'GRAY',
                    ];
                }

                // Add default value
                if ($param['default'] !== null) {
                    $defaultValue = is_bool($param['default'])
                        ? ($param['default'] ? 'true' : 'false')
                        : $param['default'];
                    $sections[] = [
                        'text' => "    Default: {$defaultValue}",
                        'color' => 'YELLOW',
                    ];
                }
            }
        }

        // Examples
        if (! empty($this->examples)) {
            $sections[] = ['text' => "", 'color' => 'WHITE'];
            $sections[] = [
                'text' => "EXAMPLES:",
                'color' => 'BRIGHT_YELLOW',
            ];

            foreach ($this->examples as $i => $example) {
                $sections[] = [
                    'text' => "  " . ($i + 1) . ". {$example['description']}",
                    'color' => 'WHITE',
                ];
                $sections[] = [
                    'text' => "     {$example['command']}",
                    'color' => 'BRIGHT_GREEN',
                ];
            }
        }

        return $sections;
    }

    /**
     * Get quick summary for lists
     */
    public function getQuickSummary(): string
    {
        $summary = $this->name;

        if (! empty($this->description)) {
            $firstLine = strtok($this->description, "\n");
            $summary .= " - " . $firstLine;
        }

        if (! empty($this->parameters)) {
            $paramCount = count($this->parameters);
            $requiredCount = count(array_filter($this->parameters, fn ($p) => $p['required']));
            $summary .= " ({$requiredCount}/{$paramCount} params)";
        }

        return $summary;
    }

    /**
     * Get parameter summary
     */
    public function getParameterSummary(): string
    {
        if (empty($this->parameters)) {
            return "No parameters";
        }

        $required = array_filter($this->parameters, fn ($p) => $p['required']);
        $optional = array_filter($this->parameters, fn ($p) => ! $p['required']);

        $summary = [];
        if (! empty($required)) {
            $summary[] = count($required) . " required";
        }
        if (! empty($optional)) {
            $summary[] = count($optional) . " optional";
        }

        return implode(', ', $summary) . " parameters";
    }

    /**
     * Check if command has parameters
     */
    public function hasParameters(): bool
    {
        return ! empty($this->parameters);
    }

    /**
     * Check if command has required parameters
     */
    public function hasRequiredParameters(): bool
    {
        return ! empty(array_filter($this->parameters, fn ($p) => $p['required']));
    }

    /**
     * Get all aliases including the main name
     */
    public function getAllNames(): array
    {
        return array_merge([$this->name], $this->aliases);
    }

    /**
     * Wrap text to specified width with indent
     */
    private function wrapText(string $text, int $indent = 0): string
    {
        $width = 76 - $indent;
        $indentStr = str_repeat(' ', $indent);

        $lines = explode("\n", $text);
        $wrappedLines = [];

        foreach ($lines as $line) {
            if (empty($line)) {
                $wrappedLines[] = $indentStr;

                continue;
            }

            $wrapped = wordwrap($line, $width, "\n", true);
            $subLines = explode("\n", $wrapped);

            foreach ($subLines as $subLine) {
                $wrappedLines[] = $indentStr . $subLine;
            }
        }

        return implode("\n", $wrappedLines);
    }

    /**
     * Create empty help object
     */
    public static function empty(string $className): self
    {
        return new self(
            name: 'unknown',
            description: 'No help available',
            usage: 'unknown',
            parameters: [],
            examples: [],
            className: $className,
            methodName: '__invoke'
        );
    }

    /**
     * Convert to array format
     */
    public function toArray(): array
    {
        return [
            'name' => $this->name,
            'description' => $this->description,
            'usage' => $this->usage,
            'parameters' => $this->parameters,
            'examples' => $this->examples,
            'className' => $this->className,
            'methodName' => $this->methodName,
            'aliases' => $this->aliases,
            'summary' => [
                'parameter_count' => count($this->parameters),
                'required_parameters' => count(array_filter($this->parameters, fn ($p) => $p['required'])),
                'has_examples' => ! empty($this->examples),
                'quick_summary' => $this->getQuickSummary(),
            ],
        ];
    }
}
