<?php

namespace Modules\AiAgent\Filament\Pages;

use BackedEnum;
use Filament\Actions\Action;
use Filament\Forms\Components\KeyValue;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Pages\Page;
use Filament\Schemas\Components\Component;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Pagination\LengthAwarePaginator;
use Modules\AiAgent\Filament\Concerns\HandlesBnfexpressErrors;
use Modules\Shared\Bnfexpress\BnfexpressAdminClient;
use UnitEnum;

/**
 * Manage EV FAQs stored by bnfexpress — data isn't Eloquent-backed, so the
 * table is fed via Table::records() (Filament's documented "custom data"
 * mechanism) rather than a query, and row/header actions use plain
 * Filament\Actions\Action instead of EditAction/DeleteAction (which assume
 * a Model).
 */
class ManageFaqs extends Page implements HasTable
{
    use HandlesBnfexpressErrors;
    use InteractsWithTable;

    protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedQuestionMarkCircle;

    protected static string|UnitEnum|null $navigationGroup = 'AI Agent';

    protected static ?string $navigationLabel = 'EV FAQs';

    protected static ?string $title = 'EV FAQs';

    protected string $view = 'ai-agent::filament.pages.manage-faqs';

    public static function canAccess(): bool
    {
        return auth()->user()?->can('manage_ai_agent') ?? false;
    }

    public function table(Table $table): Table
    {
        return $table
            ->records(function (?string $search, array $filters, int $page, int $recordsPerPage): LengthAwarePaginator {
                $result = app(BnfexpressAdminClient::class)->listFaqs(
                    q: $search,
                    search: $filters['search_mode']['value'] ?? 'normal',
                    limit: $recordsPerPage,
                    offset: ($page - 1) * $recordsPerPage,
                );

                return $this->paginate($result, 'faqs', $page, $recordsPerPage);
            })
            ->columns([
                TextColumn::make('id'),
                TextColumn::make('content')
                    ->limit(80)
                    ->wrap(),
                TextColumn::make('metadata')
                    ->formatStateUsing(fn (mixed $state): string => json_encode($state ?? [], JSON_THROW_ON_ERROR))
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->searchable()
            ->filters([
                SelectFilter::make('search_mode')
                    ->label('Search mode')
                    ->options([
                        'normal' => 'Normal (substring)',
                        'semantic' => 'Semantic (meaning-based)',
                    ])
                    ->default('normal'),
            ])
            ->recordActions([
                $this->editAction(),
                $this->deleteAction(),
            ])
            ->headerActions([
                $this->createAction(),
            ]);
    }

    protected function createAction(): Action
    {
        return Action::make('create')
            ->label('New FAQ')
            ->icon(Heroicon::OutlinedPlus)
            ->schema($this->formSchema())
            ->action(function (array $data): void {
                $this->callBnfexpress(
                    fn () => app(BnfexpressAdminClient::class)->createFaq($data['content'], $data['metadata'] ?? []),
                    successTitle: 'FAQ created',
                    failureTitle: 'Failed to create FAQ',
                );

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

    protected function editAction(): Action
    {
        return Action::make('edit')
            ->icon(Heroicon::OutlinedPencilSquare)
            ->fillForm(fn (array $record): array => $record)
            ->schema($this->formSchema())
            ->action(function (array $data, array $record): void {
                $this->callBnfexpress(
                    fn () => app(BnfexpressAdminClient::class)->updateFaq($record['id'], $data['content'], $data['metadata'] ?? []),
                    successTitle: 'FAQ updated',
                    failureTitle: 'Failed to update FAQ',
                );

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

    protected function deleteAction(): Action
    {
        return Action::make('delete')
            ->color('danger')
            ->icon(Heroicon::OutlinedTrash)
            ->requiresConfirmation()
            ->action(function (array $record): void {
                $this->callBnfexpress(
                    fn () => app(BnfexpressAdminClient::class)->deleteFaq($record['id']),
                    successTitle: 'FAQ deleted',
                    failureTitle: 'Failed to delete FAQ',
                );

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

    /**
     * @return array<int, Component>
     */
    protected function formSchema(): array
    {
        return [
            MarkdownEditor::make('content')
                ->fileAttachments(false)
                ->required(),
            KeyValue::make('metadata'),
        ];
    }

    /**
     * bnfexpress's list/faqs and list/agent-instructions endpoints return a
     * bare JSON array (confirmed live via `php artisan bnfexpress:smoke-test`),
     * with no total/limit/offset envelope — so there's no real total to
     * report, and this falls back to a "there might be one more page"
     * heuristic (also tolerates a {total, <$itemsKey>} envelope, in case
     * that ever changes).
     *
     * @param  array<string, mixed>  $result
     */
    private function paginate(array $result, string $itemsKey, int $page, int $recordsPerPage): LengthAwarePaginator
    {
        $items = $result[$itemsKey] ?? (array_is_list($result) ? $result : []);

        $total = $result['total'] ?? (($page - 1) * $recordsPerPage) + count($items) + (count($items) === $recordsPerPage ? 1 : 0);

        return new LengthAwarePaginator(
            items: collect($items)->mapWithKeys(fn (array $item): array => [$item['id'] => $item]),
            total: $total,
            perPage: $recordsPerPage,
            currentPage: $page,
        );
    }
}
