<?php

namespace App\Filament\Resources\GuideResource\Pages;

use App\Filament\Resources\GuideResource;
use App\Models\GuidePage;
use App\Models\GuidePageEdge;
use Filament\Actions\Action;
use Filament\Forms;
use Filament\Resources\Pages\Concerns\InteractsWithRecord;
use Filament\Resources\Pages\Page;

class ManageGuidePages extends Page
{
    use InteractsWithRecord;

    protected static string $resource = GuideResource::class;

    protected static string $view = 'filament.resources.guide.manage-pages';

    protected ?string $maxContentWidth = 'full';

    public array $nodes = [];

    public array $edges = [];

    public function mount(int|string $record): void
    {
        $this->record = $this->resolveRecord($record);
        $this->loadGraph();
    }

    public function getTitle(): string
    {
        return $this->getRecord()->name.' - 页面流程';
    }

    public function loadGraph(): void
    {
        $pages = $this->getRecord()->pages()->get();
        $edgeModels = $this->getRecord()->edges()->orderBy('sort')->get();

        // Build adjacency list
        $children = [];
        foreach ($pages as $p) {
            $children[$p->id] = [];
        }
        foreach ($edgeModels as $e) {
            if (isset($children[$e->from_page_id])) {
                $children[$e->from_page_id][] = $e->to_page_id;
            }
        }

        // BFS from entry nodes (no incoming edges) to assign levels
        $hasIncoming = array_flip($edgeModels->pluck('to_page_id')->toArray());
        $levels = [];
        $visited = [];
        $queue = [];

        foreach ($pages as $p) {
            if (! isset($hasIncoming[$p->id])) {
                $queue[] = $p->id;
                $levels[$p->id] = 0;
                $visited[$p->id] = true;
            }
        }

        while (! empty($queue)) {
            $cur = array_shift($queue);
            foreach ($children[$cur] ?? [] as $child) {
                if (! isset($visited[$child])) {
                    $visited[$child] = true;
                    $levels[$child] = $levels[$cur] + 1;
                    $queue[] = $child;
                }
            }
        }

        // Orphans at bottom
        $maxLevel = empty($levels) ? 0 : max($levels);
        foreach ($pages as $p) {
            if (! isset($levels[$p->id])) {
                $levels[$p->id] = $maxLevel + 1;
            }
        }

        // Group by level
        $levelGroups = [];
        foreach ($pages as $p) {
            $levelGroups[$levels[$p->id]][] = $p->id;
        }
        ksort($levelGroups);

        // Compute positions: center each level vertically, stack horizontally (left-to-right)
        $nodeWidth  = 180;  // matches CSS max-width
        $nodeHeight = 80;   // compact node height
        $gapX = 110;        // horizontal gap between levels
        $gapY = 30;         // vertical gap within same level
        $positions = [];

        foreach ($levelGroups as $level => $ids) {
            $count = count($ids);
            $totalHeight = $count * $nodeHeight + ($count - 1) * $gapY;
            $startY = max(20, (600 - $totalHeight) / 2);
            foreach ($ids as $i => $id) {
                $positions[$id] = [
                    'x' => 40 + $level * ($nodeWidth + $gapX),
                    'y' => (int) ($startY + $i * ($nodeHeight + $gapY)),
                ];
            }
        }

        $this->nodes = $pages->map(fn (GuidePage $p) => [
            'id' => $p->id,
            'title' => $p->title,
            'uri' => $p->uri,
            'is_entry' => ! isset($hasIncoming[$p->id]),
            'options' => $p->options ?? [],
            'x' => $positions[$p->id]['x'] ?? 50,
            'y' => $positions[$p->id]['y'] ?? 50,
        ])->values()->toArray();

        $this->edges = $edgeModels->map(fn (GuidePageEdge $e) => [
            'id' => $e->id,
            'from' => $e->from_page_id,
            'to' => $e->to_page_id,
            'label' => $e->label,
        ])->values()->toArray();
    }

    // -- Livewire methods called by Drawflow events --

    private function dispatchGraphUpdated(): void
    {
        $this->dispatch('graphUpdated', nodes: $this->nodes, edges: $this->edges);
    }

    public function addEdge(int $fromPageId, int $toPageId, string $outputClass = 'output_1'): void
    {
        $guide = $this->getRecord();

        if (
            ! $guide->pages()->where('id', $fromPageId)->exists() ||
            ! $guide->pages()->where('id', $toPageId)->exists()
        ) {
            return;
        }

        if ($fromPageId === $toPageId) {
            return;
        }

        $exists = $guide->edges()
            ->where('from_page_id', $fromPageId)
            ->where('to_page_id', $toPageId)
            ->exists();

        if ($exists) {
            return;
        }

        // Derive label from output port → page options mapping
        $page = $guide->pages()->find($fromPageId);
        $options = $page->options ?? [];
        $label = null;

        if (! empty($options)) {
            $outputIndex = (int) str_replace('output_', '', $outputClass) - 1;
            $label = $options[$outputIndex] ?? null;
        }

        $guide->edges()->create([
            'from_page_id' => $fromPageId,
            'to_page_id' => $toPageId,
            'label' => $label,
        ]);

        $this->loadGraph();
        $this->dispatchGraphUpdated();
    }

    public function removeEdge(int $fromPageId, int $toPageId): void
    {
        $this->getRecord()->edges()
            ->where('from_page_id', $fromPageId)
            ->where('to_page_id', $toPageId)
            ->delete();

        $this->loadGraph();
        $this->dispatchGraphUpdated();
    }

    // -- Filament Actions --

    public function createPageAction(): Action
    {
        return Action::make('createPage')
            ->label('添加页面')
            ->icon('heroicon-o-plus')
            ->form($this->getPageFormSchema())
            ->action(function (array $data): void {
                $this->getRecord()->pages()->create($data);

                $this->loadGraph();
                $this->dispatchGraphUpdated();
            });
    }

    public function editPageAction(): Action
    {
        return Action::make('editPage')
            ->label('编辑页面')
            ->icon('heroicon-o-pencil-square')
            ->mountUsing(function (Forms\Form $form, array $arguments): void {
                $page = $this->getRecord()->pages()->findOrFail($arguments['id']);
                $form->fill([
                    'title' => $page->title,
                    'content' => $page->normalized_content,
                    'options' => $page->options ?? [],
                ]);
            })
            ->form($this->getPageFormSchema())
            ->action(function (array $data, array $arguments): void {
                $page = $this->getRecord()->pages()->findOrFail($arguments['id']);
                $page->update($data);

                $this->loadGraph();
                $this->dispatchGraphUpdated();
            });
    }

    public function deletePageAction(): Action
    {
        return Action::make('deletePage')
            ->label('删除页面')
            ->icon('heroicon-o-trash')
            ->color('danger')
            ->requiresConfirmation()
            ->action(function (array $arguments): void {
                $page = $this->getRecord()->pages()->findOrFail($arguments['id']);
                $page->delete();

                $this->loadGraph();
                $this->dispatchGraphUpdated();
            });
    }

    public function deleteEdgeAction(): Action
    {
        return Action::make('deleteEdge')
            ->label('删除连线')
            ->icon('heroicon-o-trash')
            ->color('danger')
            ->requiresConfirmation()
            ->action(function (array $arguments): void {
                $edge = $this->getRecord()->edges()->findOrFail($arguments['id']);
                $edge->delete();

                $this->loadGraph();
                $this->dispatchGraphUpdated();
            });
    }

    private function getPageFormSchema(): array
    {
        return [
            Forms\Components\TextInput::make('title')
                ->label('页面标题')
                ->required()
                ->maxLength(255),

            Forms\Components\RichEditor::make('content')
                ->label('页面内容')
                ->required()
                ->fileAttachmentsDisk('public')
                ->fileAttachmentsDirectory('guide-pages')
                ->fileAttachmentsVisibility('public')
                ->getUploadedAttachmentUrlUsing(fn (string $file): string => GuidePage::uploadedAttachmentUrl($file))
                ->dehydrateStateUsing(fn (?string $state): string => GuidePage::normalizeRichTextContent($state))
                ->columnSpanFull(),

            Forms\Components\TagsInput::make('options')
                ->label('分支选项')
                ->helperText('定义此页面的分支按钮（每个选项对应一个输出端口）。留空 = 顺序页面。'),
        ];
    }
}
