<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Filament\HostPluginCenter\Widgets;

use App\Filament\HostPluginCenter\Concerns\InteractsWithHostPluginOperations;
use App\Support\HostPluginCenterDisplay;
use Filament\Actions\Action;
use Filament\Support\Enums\FontWeight;
use Filament\Support\Enums\Width;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Str;
use Livewire\Attributes\On;

final class CatalogPluginsTableWidget extends HostPluginCenterTableWidget
{
    use InteractsWithHostPluginOperations;

    public bool $pluginInstallInProgress = false;

    public ?string $installingPluginCode = null;

    #[On('plugin-center-data-changed')]
    public function refreshCatalogPluginsTable(): void
    {
        app(HostPluginCenterDisplay::class)->clearCatalogCache();
        $this->resetTable();
    }

    public function table(Table $table): Table
    {
        $display = app(HostPluginCenterDisplay::class);

        return $table
            ->heading(null)
            ->queryStringIdentifier('hostPluginCatalog')
            ->paginated(false)
            ->records(fn (?string $search, array $filters): array => $this->catalogPluginRecords($search, $filters))
            ->emptyStateHeading(fn (): string => $display->catalogFetchErrorMessage() !== null
                ? (string) __('dberp.plugin_center.catalog.fetch_failed_title')
                : (string) __('dberp.empty_states.default_empty'))
            ->emptyStateDescription($display->catalogEmptyMessage())
            ->emptyStateIcon('heroicon-o-cloud-arrow-down')
            ->emptyStateActions([
                Action::make('retryCatalog')
                    ->label(__('dberp.plugin_center.actions.retry'))
                    ->icon('heroicon-o-arrow-path')
                    ->visible(fn (): bool => $display->catalogFetchErrorMessage() !== null)
                    ->action(function () use ($display): void {
                        $display->clearCatalogCache();
                        $this->resetTable();
                    }),
            ])
            ->columns([
                Stack::make([
                    TextColumn::make('plugin_name')
                        ->label(__('dberp.plugin_center.catalog.columns.name'))
                        ->icon('heroicon-o-puzzle-piece')
                        ->weight(FontWeight::SemiBold)
                        ->size('lg')
                        ->searchable()
                        ->wrap(),
                    TextColumn::make('description')
                        ->label(__('dberp.plugin_center.catalog.columns.description'))
                        ->placeholder('—')
                        ->color('gray')
                        ->lineClamp(3)
                        ->wrap(),
                    TextColumn::make('state_label')
                        ->label(__('dberp.plugin_center.catalog.columns.status'))
                        ->badge()
                        ->color(fn (array $record): string => (string) ($record['state_color'] ?? 'gray')),
                    TextColumn::make('latest_version')
                        ->label(__('dberp.plugin_center.catalog.columns.version'))
                        ->icon('heroicon-o-tag')
                        ->prefix(__('dberp.plugin_center.catalog.version_prefix'))
                        ->placeholder(__('dberp.plugin_center.installed.version_unknown')),
                ])->space(2),
            ])
            ->contentGrid([
                'md' => 2,
                '2xl' => 3,
            ])
            ->filters([
                SelectFilter::make('state')
                    ->label(__('dberp.plugin_center.catalog.columns.status'))
                    ->options([
                        'installable' => __('dberp.plugin_center.catalog.state.installable'),
                        'incompatible_version' => __('dberp.plugin_center.catalog.state.incompatible_version'),
                        'installed' => __('dberp.plugin_center.catalog.state.installed'),
                        'update_available' => __('dberp.plugin_center.catalog.state.update_available'),
                        'unavailable' => __('dberp.plugin_center.catalog.state.unavailable'),
                    ]),
            ])
            ->recordActions([
                Action::make('details')
                    ->label(__('dberp.plugin_center.actions.details'))
                    ->icon('heroicon-o-information-circle')
                    ->color('gray')
                    ->slideOver()
                    ->modalWidth(Width::Large)
                    ->modalHeading(fn (array $record): string => (string) ($record['plugin_name'] ?? ''))
                    ->modalDescription(__('dberp.plugin_center.catalog.detail_heading'))
                    ->modalContent(fn (array $record): View => view('filament.host-plugin-center.catalog-detail-panel', [
                        'record' => $record,
                    ]))
                    ->modalSubmitAction(false)
                    ->modalCancelActionLabel(__('filament-actions::view.single.modal.actions.close.label')),
                Action::make('install')
                    ->label(fn (array $record): string => filled($record['installed_version'] ?? null)
                        ? (string) __('dberp.plugin_center.catalog.state.installed')
                        : (string) __('dberp.plugin_center.actions.install'))
                    ->color('primary')
                    ->icon('heroicon-o-arrow-down-tray')
                    ->requiresConfirmation()
                    ->modalHeading(__('dberp.plugin_center.confirm.install_heading'))
                    ->modalDescription(fn (array $record): string => (string) __(
                        'dberp.plugin_center.confirm.install',
                        [
                            'name' => (string) ($record['plugin_name'] ?? ''),
                            'version' => (string) ($record['latest_version'] ?? ''),
                        ],
                    ))
                    ->disabled(fn (array $record): bool => ! (bool) ($record['show_install_action'] ?? false)
                        || ($this->pluginInstallInProgress
                            && $this->installingPluginCode === ($record['plugin_code'] ?? null)))
                    ->tooltip(fn (array $record): ?string => (string) ($record['install_blocked_reason'] ?? '') ?: null)
                    ->action(function (array $record): void {
                        $this->installOfficialPlugin(
                            (string) ($record['plugin_code'] ?? ''),
                            filled($record['latest_version'] ?? null) ? (string) $record['latest_version'] : null,
                        );

                        $this->resetTable();
                    }),
            ]);
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function catalogPluginRecords(?string $search = null, array $filters = []): array
    {
        $records = [];

        foreach (app(HostPluginCenterDisplay::class)->catalogRows() as $row) {
            $pluginCode = (string) ($row['plugin_code'] ?? '');

            if ($pluginCode === '') {
                continue;
            }

            if (filled($search) && ! Str::contains(
                Str::lower(implode(' ', [
                    $pluginCode,
                    (string) ($row['plugin_name'] ?? ''),
                    (string) ($row['description'] ?? ''),
                ])),
                Str::lower((string) $search),
            )) {
                continue;
            }

            $stateFilter = $filters['state']['value'] ?? null;

            if (filled($stateFilter) && ($row['state'] ?? null) !== $stateFilter) {
                continue;
            }

            $records[$pluginCode] = $row;
        }

        return $records;
    }
}
