<?php

declare(strict_types=1);

namespace App\Filament\Support;

use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Actions\ViewAction;
use Filament\Infolists\Components\TextEntry;
use Filament\Support\Enums\IconSize;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\Column;
use Filament\Tables\Columns\TextColumn;
use Filament\Widgets\StatsOverviewWidget\Stat;
use ReflectionProperty;

/**
 * 全站 Filament UI 图标统一注册入口（在 AdminPanelProvider::boot 调用）。
 */
final class DberpFilamentActionConfigurator
{
    public static function registerDefaults(): void
    {
        self::registerActionDefaults();
        self::registerInfolistDefaults();
    }

    private static function registerActionDefaults(): void
    {
        Action::configureUsing(static function (Action $action): void {
            self::configureAction($action);
        }, isImportant: true);

        BulkAction::configureUsing(static function (BulkAction $action): void {
            self::configureAction($action);
        }, isImportant: true);

        CreateAction::configureUsing(static function (CreateAction $action): void {
            self::configureAction($action);

            if ($action->getIcon() === null) {
                $action->icon($action->getGroupedIcon() ?? Heroicon::Plus);
            }
        }, isImportant: true);

        EditAction::configureUsing(static function (EditAction $action): void {
            self::configureAction($action);

            if ($action->getIcon() === null) {
                $action->icon($action->getTableIcon() ?? Heroicon::PencilSquare);
            }
        }, isImportant: true);

        DeleteAction::configureUsing(static function (DeleteAction $action): void {
            self::configureAction($action);

            if ($action->getIcon() === null) {
                $action->icon($action->getTableIcon() ?? Heroicon::Trash);
            }
        }, isImportant: true);

        ViewAction::configureUsing(static function (ViewAction $action): void {
            self::configureAction($action);

            if ($action->getIcon() === null) {
                $action->icon($action->getTableIcon() ?? Heroicon::Eye);
            }
        }, isImportant: true);

        TextColumn::configureUsing(static function (TextColumn $column): void {
            if (self::columnHasIcon($column) || ! self::columnHasUrl($column)) {
                return;
            }

            $icon = DberpFilamentLinkColumnIconResolver::forColumnName($column->getName());

            if ($icon !== null) {
                $column->icon($icon);
            }
        }, isImportant: true);

        Stat::configureUsing(static function (Stat $stat): void {
            if ($stat->getIcon() !== null || ! self::statHasUrl($stat)) {
                return;
            }

            $stat->icon(DberpFilamentLinkColumnIconResolver::forStatDescription(
                self::resolveStatDescription($stat),
            ));
        }, isImportant: true);
    }

    private static function registerInfolistDefaults(): void
    {
        if (! class_exists(TextEntry::class)) {
            return;
        }

        TextEntry::configureUsing(static function (TextEntry $entry): void {
            if (self::infolistEntryHasIcon($entry)) {
                return;
            }

            $icon = DberpFilamentInfolistIconResolver::entry($entry->getName());

            if ($icon !== null) {
                $entry->icon($icon);
            }
        }, isImportant: true);
    }

    public static function configureAction(Action $action): void
    {
        self::applyDefaultIcon($action);
        self::applyDefaultIconSize($action);
    }

    public static function applyDefaultIcon(Action $action): void
    {
        if ($action->getIcon() !== null) {
            return;
        }

        $icon = DberpFilamentActionIconResolver::forActionName($action->getName());

        if ($icon === null && $action->getTable() !== null) {
            $icon = $action->getTableIcon();
        }

        if ($icon === null) {
            $icon = $action->getGroupedIcon();
        }

        if ($icon !== null) {
            $action->icon($icon);
        }
    }

    public static function applyDefaultIconSize(Action $action): void
    {
        if ($action->getIconSize() !== null) {
            return;
        }

        $action->iconSize(IconSize::Small);
    }

    private static function columnHasIcon(Column $column): bool
    {
        $icon = (new ReflectionProperty($column, 'icon'))->getValue($column);

        return filled($icon) && $icon !== false;
    }

    private static function infolistEntryHasIcon(TextEntry $entry): bool
    {
        $icon = (new ReflectionProperty($entry, 'icon'))->getValue($entry);

        return filled($icon) && $icon !== false;
    }

    private static function columnHasUrl(Column $column): bool
    {
        $url = (new ReflectionProperty($column, 'url'))->getValue($column);

        return filled($url);
    }

    private static function statHasUrl(Stat $stat): bool
    {
        $url = (new ReflectionProperty($stat, 'url'))->getValue($stat);

        return filled($url);
    }

    private static function resolveStatDescription(Stat $stat): ?string
    {
        $description = $stat->getDescription();

        return is_string($description) ? $description : null;
    }
}
