<?php

declare(strict_types=1);

namespace App\Framework\View\Table;

final readonly class Table
{
    /**
     * @param TableColumn[] $columns
     * @param TableRow[] $rows
     */
    public function __construct(
        public array $columns,
        public array $rows,
        public ?string $cssClass = null,
        public ?TableOptions $options = null,
        public ?string $id = null
    ) {
    }

    public function render(): string
    {
        $options = $this->options ?? new TableOptions();

        $classString = $this->buildClassString($options);
        $attributesString = $this->buildAttributesString($options);
        $idString = $this->id ? " id=\"{$this->id}\"" : '';

        $thead = $this->renderThead();
        $tbody = $this->renderTbody($options);

        return "<table{$classString}{$idString}{$attributesString}>{$thead}{$tbody}</table>";
    }

    private function renderThead(): string
    {
        $headerCells = array_map(fn (TableColumn $column) => $column->renderHeader(), $this->columns);

        return "<thead><tr>" . implode('', $headerCells) . "</tr></thead>";
    }

    private function renderTbody(TableOptions $options): string
    {
        if (empty($this->rows)) {
            $colspan = count($this->columns);
            $emptyMessage = $options->emptyMessage ?? 'No data available';

            return "<tbody><tr><td colspan=\"{$colspan}\" class=\"text-center empty-message\">{$emptyMessage}</td></tr></tbody>";
        }

        $rowsHtml = array_map(fn (TableRow $row) => $row->render(), $this->rows);

        return "<tbody>" . implode('', $rowsHtml) . "</tbody>";
    }

    private function buildClassString(TableOptions $options): string
    {
        $classes = [];

        if ($this->cssClass) {
            $classes[] = $this->cssClass;
        }

        if ($options->striped) {
            $classes[] = 'table-striped';
        }

        if ($options->bordered) {
            $classes[] = 'table-bordered';
        }

        if ($options->hover) {
            $classes[] = 'table-hover';
        }

        if ($options->responsive) {
            $classes[] = 'table-responsive';
        }

        return $classes ? ' class="' . implode(' ', $classes) . '"' : '';
    }

    private function buildAttributesString(TableOptions $options): string
    {
        if (! $options->tableAttributes) {
            return '';
        }

        $parts = [];
        foreach ($options->tableAttributes as $key => $value) {
            $parts[] = $key . '="' . htmlspecialchars((string) $value, ENT_QUOTES) . '"';
        }

        return $parts ? ' ' . implode(' ', $parts) : '';
    }

    /**
     * Create table from array data with column definitions
     */
    public static function fromArray(array $data, array $columnDefs, ?TableOptions $options = null): self
    {
        $columns = [];
        $rows = [];

        // Build columns
        foreach ($columnDefs as $key => $def) {
            if (is_string($def)) {
                // Simple string header
                $columns[] = TableColumn::text($key, $def);
            } elseif ($def instanceof TableColumn) {
                // Already a TableColumn
                $columns[] = $def;
            } elseif (is_array($def)) {
                // Array definition
                $columns[] = new TableColumn(
                    key: $key,
                    header: $def['header'] ?? $key,
                    cssClass: $def['class'] ?? null,
                    formatter: $def['formatter'] ?? null,
                    sortable: $def['sortable'] ?? false,
                    width: $def['width'] ?? null,
                    defaultType: $def['type'] ?? null
                );
            }
        }

        // Build rows
        foreach ($data as $rowData) {
            $rows[] = TableRow::fromData($rowData, $columns);
        }

        return new self($columns, $rows, null, $options);
    }

    /**
     * Create simple table from 2D array
     */
    public static function fromSimpleArray(array $headers, array $data, ?TableOptions $options = null): self
    {
        $columns = array_map(
            fn ($header, $index) => TableColumn::text((string) $index, $header),
            $headers,
            array_keys($headers)
        );

        $rows = array_map(
            fn ($rowData) => TableRow::fromValues($rowData),
            $data
        );

        return new self($columns, $rows, null, $options);
    }

    /**
     * Create environment variables table
     */
    public static function forEnvironmentVars(array $env): self
    {
        $columns = [
            TableColumn::text('key', 'Variable', 'env-key'),
            TableColumn::text('value', 'Wert', 'env-value'),
        ];

        $rows = [];
        foreach ($env as $key => $value) {
            // Mask sensitive values - ensure key is string
            $displayValue = self::maskSensitiveValue((string) $key, $value);

            $rows[] = TableRow::fromData([
                'key' => (string) $key,
                'value' => $displayValue,
            ], $columns, 'env-row');
        }

        return new self(
            columns: $columns,
            rows: $rows,
            cssClass: 'admin-table',
            options: TableOptions::admin(),
            id: 'envTable'
        );
    }

    /**
     * Create migrations table
     */
    public static function forMigrations(array $migrations): self
    {
        $columns = [
            TableColumn::withFormatter(
                'status',
                'Status',
                Formatters\StatusFormatter::withBadges(),
                'status-col'
            ),
            TableColumn::text('version', 'Version', 'version-col'),
            TableColumn::text('description', 'Description', 'description-col'),
            TableColumn::withFormatter(
                'applied',
                'Applied',
                Formatters\BooleanFormatter::germanWithBadges(),
                'applied-col'
            ),
        ];

        $rows = [];
        foreach ($migrations as $migration) {
            $statusData = [
                'status_icon' => $migration['status_icon'] ?? '',
                'status_text' => $migration['status_text'] ?? '',
                'status_class' => $migration['status_class'] ?? 'secondary',
            ];

            $rows[] = TableRow::fromData([
                'status' => $statusData,
                'version' => $migration['version'] ?? '',
                'description' => $migration['description'] ?? '',
                'applied' => $migration['applied'] ?? false,
            ], $columns, 'migration-row');
        }

        return new self(
            columns: $columns,
            rows: $rows,
            cssClass: 'admin-table',
            options: TableOptions::admin(),
            id: 'migrationsTable'
        );
    }

    private static function maskSensitiveValue(string $key, mixed $value): string
    {
        $sensitiveKeys = ['password', 'secret', 'key', 'token', 'auth'];

        foreach ($sensitiveKeys as $sensitiveKey) {
            if (stripos($key, $sensitiveKey) !== false) {
                return '********';
            }
        }

        // Handle arrays and objects properly
        if (is_array($value)) {
            $encoded = json_encode($value, JSON_PRETTY_PRINT);

            return $encoded ?: '[Array]';
        }

        if (is_object($value)) {
            if (method_exists($value, '__toString')) {
                return (string) $value;
            }

            return get_class($value);
        }

        return (string) $value;
    }
}
