<?php

namespace App\Filament\Pages;

use App\Exceptions\LogisticsApiException;
use App\Services\LogisticsService;
use App\Support\ApiErrorTranslator;
use Filament\Pages\Page;
use Filament\Support\Icons\Heroicon;
use Livewire\Attributes\Url;

class TablesExplorer extends Page
{
    protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedTableCells;

    protected static ?string $navigationLabel = 'Tables';

    protected static ?string $title = 'Explorateur de tables';

    protected static ?int $navigationSort = 1;

    protected string $view = 'filament.pages.tables-explorer';

    #[Url]
    public string $selectedTable = '';

    public string $tableFilter = '';

    public array $tables = [];

    public array $columns = [];

    public ?array $tablesMetadata = null;

    public ?array $columnsMetadata = null;

    public ?string $errorMessage = null;

    /**
     * @var array<string, string>
     */
    private static array $dataTypeLabels = [
        'C' => 'Caractère',
        'N' => 'Numérique',
        'T' => 'Date/Heure',
        'D' => 'Date',
        'L' => 'Logique',
        'M' => 'Mémo',
    ];

    public function mount(): void
    {
        $this->loadTables();

        if (filled($this->selectedTable)) {
            $this->loadColumns();
        }
    }

    public function selectTable(string $tableName): void
    {
        $this->selectedTable = $tableName;
        $this->loadColumns();
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function getFilteredTablesProperty(): array
    {
        if (blank($this->tableFilter)) {
            return $this->tables;
        }

        $filter = mb_strtolower($this->tableFilter);

        return array_values(array_filter(
            $this->tables,
            fn (array $table): bool => str_contains(mb_strtolower($table['name'] ?? ''), $filter),
        ));
    }

    public static function getDataTypeLabel(string $type): string
    {
        return self::$dataTypeLabels[strtoupper($type)] ?? $type;
    }

    private function loadTables(): void
    {
        try {
            $service = app(LogisticsService::class);
            $response = $service->tablesList();

            $this->tables = $response['data'] ?? [];
            $this->tablesMetadata = $response['metadata'] ?? null;
            $this->errorMessage = ApiErrorTranslator::translate($response['error'] ?? null);
        } catch (LogisticsApiException $e) {
            $this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
        } catch (\Throwable $e) {
            $this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
        }
    }

    private function loadColumns(): void
    {
        if (blank($this->selectedTable)) {
            $this->columns = [];
            $this->columnsMetadata = null;

            return;
        }

        try {
            $service = app(LogisticsService::class);
            $response = $service->columnList($this->selectedTable);

            $rawColumns = $response['data'] ?? [];
            $this->columns = $this->deduplicateColumns($rawColumns);
            $this->columnsMetadata = $response['metadata'] ?? null;
            $this->errorMessage = ApiErrorTranslator::translate($response['error'] ?? null);
        } catch (LogisticsApiException $e) {
            $this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
            $this->columns = [];
        } catch (\Throwable $e) {
            $this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
            $this->columns = [];
        }
    }

    /**
     * @param  array<int, array<string, mixed>>  $columns
     * @return array<int, array<string, mixed>>
     */
    private function deduplicateColumns(array $columns): array
    {
        $seen = [];
        $unique = [];

        foreach ($columns as $column) {
            $key = ($column['name'] ?? '').'|'.($column['dataType'] ?? '');
            if (! isset($seen[$key])) {
                $seen[$key] = true;
                $unique[] = $column;
            }
        }

        return $unique;
    }
}
