<?php

declare(strict_types=1);

namespace App\Framework\View\Table\ValueObjects;

use App\Framework\View\Table\CellFormatter;
use App\Framework\View\Table\CellType;
use App\Framework\View\Table\TableColumn;

final readonly class ColumnDefinition
{
    public function __construct(
        public string $key,
        public string $header,
        public ColumnType $type,
        public ?string $cssClass = null,
        public ?CellFormatter $formatter = null,
        public bool $sortable = false,
        public ?string $width = null
    ) {
    }

    /**
     * Create a text column
     */
    public static function text(string $key, string $header, ?string $cssClass = null): self
    {
        return new self(
            key: $key,
            header: $header,
            type: ColumnType::TEXT,
            cssClass: $cssClass
        );
    }

    /**
     * Create a status column with formatter
     */
    public static function status(string $key, string $header, ?string $cssClass = null): self
    {
        return new self(
            key: $key,
            header: $header,
            type: ColumnType::STATUS,
            cssClass: $cssClass,
            formatter: \App\Framework\View\Table\Formatters\StatusFormatter::withBadges()
        );
    }

    /**
     * Create a boolean column with formatter
     */
    public static function boolean(string $key, string $header, ?string $cssClass = null): self
    {
        return new self(
            key: $key,
            header: $header,
            type: ColumnType::BOOLEAN,
            cssClass: $cssClass,
            formatter: \App\Framework\View\Table\Formatters\BooleanFormatter::germanWithBadges()
        );
    }

    /**
     * Create a column with custom formatter
     */
    public static function withFormatter(
        string $key,
        string $header,
        CellFormatter $formatter,
        ?string $cssClass = null
    ): self {
        return new self(
            key: $key,
            header: $header,
            type: ColumnType::CUSTOM,
            cssClass: $cssClass,
            formatter: $formatter
        );
    }

    /**
     * Create a numeric column
     */
    public static function numeric(string $key, string $header, ?string $cssClass = null): self
    {
        return new self(
            key: $key,
            header: $header,
            type: ColumnType::NUMERIC,
            cssClass: $cssClass
        );
    }

    /**
     * Create a date column
     */
    public static function date(string $key, string $header, ?string $cssClass = null): self
    {
        return new self(
            key: $key,
            header: $header,
            type: ColumnType::DATE,
            cssClass: $cssClass
        );
    }

    /**
     * Add sortable flag
     */
    public function sortable(): self
    {
        return new self(
            key: $this->key,
            header: $this->header,
            type: $this->type,
            cssClass: $this->cssClass,
            formatter: $this->formatter,
            sortable: true,
            width: $this->width
        );
    }

    /**
     * Set column width
     */
    public function withWidth(string $width): self
    {
        return new self(
            key: $this->key,
            header: $this->header,
            type: $this->type,
            cssClass: $this->cssClass,
            formatter: $this->formatter,
            sortable: $this->sortable,
            width: $width
        );
    }

    /**
     * Validate a value against this column's type expectations
     */
    public function validateValue(mixed $value): void
    {
        match ($this->type) {
            ColumnType::TEXT => $this->validateTextValue($value),
            ColumnType::NUMERIC => $this->validateNumericValue($value),
            ColumnType::BOOLEAN => $this->validateBooleanValue($value),
            ColumnType::DATE => $this->validateDateValue($value),
            ColumnType::STATUS => $this->validateStatusValue($value),
            ColumnType::CUSTOM => null, // Custom columns can accept any value
        };
    }

    /**
     * Convert to TableColumn for use in existing Table class
     */
    public function toTableColumn(): TableColumn
    {
        // Map our ColumnType to CellType
        $cellType = match ($this->type) {
            ColumnType::TEXT => CellType::TEXT,
            ColumnType::NUMERIC => CellType::NUMBER,
            ColumnType::BOOLEAN => CellType::BOOLEAN,
            ColumnType::DATE => CellType::DATE,
            ColumnType::STATUS => CellType::HTML, // Status uses HTML for badges
            ColumnType::CUSTOM => CellType::HTML, // Custom can be HTML
        };

        return new TableColumn(
            key: $this->key,
            header: $this->header,
            cssClass: $this->cssClass,
            formatter: $this->formatter,
            sortable: $this->sortable,
            width: $this->width,
            defaultType: $cellType
        );
    }

    private function validateTextValue(mixed $value): void
    {
        if ($value !== null && ! is_string($value) && ! is_numeric($value)) {
            throw new \InvalidArgumentException(
                "Text column '{$this->key}' expects string or numeric value, got " . gettype($value)
            );
        }
    }

    private function validateNumericValue(mixed $value): void
    {
        if ($value !== null && ! is_numeric($value)) {
            throw new \InvalidArgumentException(
                "Numeric column '{$this->key}' expects numeric value, got " . gettype($value)
            );
        }
    }

    private function validateBooleanValue(mixed $value): void
    {
        if ($value !== null && ! is_bool($value)) {
            throw new \InvalidArgumentException(
                "Boolean column '{$this->key}' expects boolean value, got " . gettype($value)
            );
        }
    }

    private function validateDateValue(mixed $value): void
    {
        if ($value !== null && ! ($value instanceof \DateTimeInterface) && ! is_string($value)) {
            throw new \InvalidArgumentException(
                "Date column '{$this->key}' expects DateTimeInterface or string, got " . gettype($value)
            );
        }
    }

    private function validateStatusValue(mixed $value): void
    {
        if ($value !== null && ! is_array($value)) {
            throw new \InvalidArgumentException(
                "Status column '{$this->key}' expects array with status data, got " . gettype($value)
            );
        }

        if (is_array($value)) {
            $requiredKeys = ['status_text', 'status_class'];
            foreach ($requiredKeys as $key) {
                if (! array_key_exists($key, $value)) {
                    throw new \InvalidArgumentException(
                        "Status column '{$this->key}' requires '{$key}' in status array"
                    );
                }
            }
        }
    }
}
