<?php

namespace App\Filament\Pages;

use App\Models\Event;
use App\Models\Inscription;
use App\Models\Modality;
use App\Models\Round as ModelRound;
use App\Models\RoundBuffer;
use App\Models\RoundForce;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Components\Wizard;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Forms\Set;
use Filament\Notifications\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Pages\Concerns\InteractsWithFormActions;
use Filament\Pages\Page;
use Illuminate\Support\HtmlString;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;

class Narrator extends Page implements HasActions, HasForms
{
    use InteractsWithFormActions;
    use InteractsWithForms;
    use HasPageShield;

    protected static ?string $navigationIcon = 'heroicon-o-megaphone';
    protected static ?string $navigationLabel = 'Narrador';
    protected static ?string $title = 'Narrador';
    protected static ?string $slug = 'narrator';
    protected static ?int $navigationSort = 1;
    protected static ?string $navigationGroup = 'Provas';
    protected static string $view = 'filament.pages.narrator';

    public array $data = [];
    public ?int $eventId = null;
    public ?int $modalityId = null;
    public $rounds;
    public $inscriptions;
    public $tableData = [];
    public bool $hasClassificationRounds = false;
    public string $group = '';
    public $round_status;
    public $resultGroup = [];
    public $isTeams = false;
    #[Reactive]
    public bool $showPendingRoundsModal = false; // Controla visibilidade do modal de rodadas pendentes
    public array $pendingRounds = []; // Armazena rodadas não finalizadas
    public bool $roundFinish = false;
    public array $pendingValues = []; // Valores temporários das rodadas pendentes

    public ?int $stepRound = 1;

    public function mount(): void
    {
        $this->eventId = null;
        $this->modalityId = null;
        $this->rounds = collect();
        $this->inscriptions = collect();
        $this->dispatch('round-updated');
    }

    public function getFormSchema(): array
    {
        return [
            Section::make([
                Select::make('eventId')
                    ->label('Selecione o evento')
                    ->options(Event::orderBy('created_at', 'desc')->pluck('name', 'id'))
                    ->reactive()
                    ->afterStateUpdated(function ($state) {
                        $this->updatedEventId($state, changeGroup: true);
                    })
                    ->required(),

                Select::make('modalityId')
                    ->label('Selecione a modalidade')
                    ->selectablePlaceholder(false)
                    ->options(function () {
                        return $this->eventId
                            ? Event::find($this->eventId)->modalities->where('status_modality', false)->pluck('name', 'id')
                            : [];
                    })

                    ->default(function() {
                        if ($this->eventId) {
                            return Event::find($this->eventId)->modalities->where( 'status_modality', 0)->first()?->id;
                        }
                        return null;
                    })
                    ->live()
                    ->reactive()
                    ->visible(fn () => filled($this->eventId))
                    ->afterStateUpdated(function ($state, Set $set) {

                        $this->updatedModalityId($state, true);
                        $this->dispatch('reset-wizard');
                        $this->data = [];
                    })
                    ->required(),

                Select::make('group')
                    ->label('Grupo')
                    ->selectablePlaceholder(false)
                    ->options(function () {
                        // Começa com a opção padrão de classificação
                        $options = [
                            'classification' => 'Rodada classificatória'
                        ];

                        // Se tiver eventId e modalityId, busca as forças disponíveis
                        if ($this->eventId && $this->modalityId) {
                            $forces = RoundForce::where([
                                'event_id' => $this->eventId,
                                'modality_id' => $this->modalityId
                            ])
                                ->distinct()
                                ->where('force', '<>', 'N/C')
                                ->pluck('force')
                                ->map(function ($force) {
                                    return ['force' => $force, 'label' => "Força {$force}"];
                                })
                                ->pluck('label', 'force')
                                ->toArray();

                            // Combina as opções
                            $options = array_merge($options, $forces);
                        }

                        return $options;
                    })
                    ->default('classification')
                    ->live()
                    ->reactive()
                    ->visible($this->hasClassificationRounds)
                    ->afterStateUpdated(function ($state) {
                        // Limpa os dados atuais
                        $this->rounds = collect();
                        $this->inscriptions = collect();

                        // Atualiza o grupo
                        $this->group = $state;

                        // Se tivermos uma modalidade selecionada, recarrega tudo
                        if ($this->modalityId) {
                            $this->updatedModalityId($this->modalityId);
                        }
                        $this->loadRounds();

                        // Reseta o wizard
                        $this->dispatch('reset-wizard');
                        $this->data = [];
                    }),
            ])
            ->columns($this->hasClassificationRounds ? 3 : 2),

            Wizard::make($this->getWizardSteps())
                ->visible($this->rounds->isNotEmpty())
                ->persistStepInQueryString('s')
                ->view('forms.components.wizard'),
        ];
    }

    public function updateView()
    {
        if ($this->modalityId && $this->eventId) {
            $this->loadRounds();
        }
    }

    public function getWizardSteps(): array
    {
        $steps = [];

        if ($this->rounds->isEmpty()) {
            return $steps;
        }

        // Gera campos para cada participante da rodada
        foreach ($this->rounds as $indexRound => $round) {
            $participantsSchema = [];
            $firstLabel = true;
            $sortedInscriptions = $round['inscriptions']->sortBy('inscription_number');

            foreach ($sortedInscriptions as $inscription) {
                foreach ($inscription->participants as $participant) {
                    $filterRoundPrevious['inscription'] = $inscription->id;
                    $filterRoundPrevious['participant'] = $participant->id;
                    $filterRoundPrevious['event'] = $this->eventId;
                    $filterRoundPrevious['modality'] = $this->modalityId;
                    $filterRoundPrevious['group'] = $this->group;
                    $filterRoundPrevious['number'] = $inscription->inscription_number;

                    $participantsSchema[] = ToggleButtons::make("data.{$round['number']}.{$inscription->id}.{$participant->id}")
                        ->label($inscription->name . '|' . $participant->name)
                        ->options([
                            '1' => 'Boa',
                            '0' => 'Branca',
                        ])
                        ->icons([
                            '1' => 'heroicon-o-hand-thumb-up',
                            '0' => 'heroicon-o-hand-thumb-down',
                        ])
                        ->colors([
                            '1' => 'success',
                            '0' => 'danger',
                        ])
                        ->view('forms.components.narrator-toggle-wizard',compact('firstLabel', 'indexRound', 'filterRoundPrevious'));
                    $firstLabel = false;
                }
            }

            // Cria step para a rodada atual
            $steps[] = Wizard\Step::make("Volta {$round['number']}")
                ->columnSpanFull()
                ->afterValidation(function () use ($round) {
                    $this->loadRounds();
                })
                ->schema($participantsSchema);
        }

        return $steps;
    }

    // Atualiza as rodadas quando o evento for alterado
    public function updatedEventId($eventId, $changeGroup = false): void
    {
        $this->eventId = $eventId;
        $this->rounds = collect();

        // Seleciona primeiro modalityId disponível
        $firstModality = Event::find($eventId)?->modalities->where('status_modality', 0)->first();
        if ($firstModality) {
            $this->modalityId = $firstModality->id;
            $this->updatedModalityId($firstModality->id, $changeGroup);
        }
    }

    // Atualiza a modalidade e configura as rodadas iniciais
    public function updatedModalityId($modalityId, $changeGroup = false, $callLoadRounds = true): void
    {
        $modality = Modality::find($modalityId);
        $this->isTeams = $modality->rules->participant_rule !== 'Individual';
        $this->hasClassificationRounds = boolval($modality->active_additional_rules ?? false);

        if ($this->hasClassificationRounds && empty($this->group)) {
            $this->group = 'classification';
            $this->handleGroupChange(['state' => 'classification']);
        }

        // Busca os participantes base
        $inscriptions = Inscription::where([
            'modality_id' => $modality->id,
            'event_id' => $this->eventId,
            'inscription_status' => 1,
        ])->where('round_lifeless', '>=', $this->stepRound)->orWhere(function($query) use ($modality) {
            $query->where([
                'modality_id' => $modality->id,
                'event_id' => $this->eventId,
                'inscription_status' => 1,
                'round_lifeless' => 0,
            ]);
        })->orWhere(function($query) use ($modality) {
            $query->where([
                'modality_id' => $modality->id,
                'event_id' => $this->eventId,
                'inscription_status' => 0,
            ])->where('round_lifeless', '>=', $this->stepRound);
        })->withCount(['rounds' => function($query) use ($modality) {
            $query->where('value', 1)
                ->where('modality_id', $modality->id)
                ->where('group', 'classification') // Sempre usa classification para contar
                ->groupBy('inscription_id');
        }])->orderBy('name')->get();

        // Se não for classification nem vazio, filtra pelos participantes que satisfazem a regra
        if ($this->group !== 'classification' && $this->group !== '') {
            $inscriptions = Inscription::where([
                'modality_id' => $modality->id,
                'event_id' => $this->eventId,
                'inscription_status' => 1,
            ])->whereHas('roundForces', function($query) use ($modality) {
                $query->where([
                    'modality_id' => $modality->id,
                    'event_id' => $this->eventId,
                    'force' => $this->group,
                ]);
            })->orderBy('name')->get();

            if ($inscriptions->isEmpty()) {
                $this->without_participants = true;
            }
        }

        // Cria as rodadas se houver participantes
        if ($inscriptions->isEmpty()) {
            $rounds = [];
        } else {
            $rounds = [];
            for($i = 1; $i <= $modality->round_initial; $i++) {
                $rounds[] = [
                    'number' => $i,
                    'inscriptions' => $inscriptions
                ];
            }
        }

        $this->rounds = collect($rounds);
        $this->inscriptions = $inscriptions;

        if ($changeGroup) {
            if ($this->hasClassificationRounds){
                $this->group = 'classification';
            } else {
                $this->group = '';
            }
        }

        // Atualiza o wizard
        $this->dispatch('refreshSteps');
        if ($callLoadRounds) {
            $this->loadRounds();
        }
    }
    protected function getRedirectUrl(): string
    {
        return $this->getResource()::getUrl('index');
    }

    public function getListeners(): array
    {
        return [
            'refreshSteps' => '$refresh',
            'pollResults' => 'updateView',
            'group-changed' => 'handleGroupChange',
        ];
    }

    //Carrega as informações necessárias para a exibição na tabela das rodadas
    public function loadRounds($NotFinish = true)
    {
        $currentStep = $this->stepRound;
        $this->roundFinish = false;
        $modality = Modality::find($this->modalityId);
        $this->updatedModalityId($this->modalityId, callLoadRounds: false);

        // Verifica se todas rodadas foram finalizadas
        $rounds = ModelRound::where('modality_id', $this->modalityId)
            ->where('event_id', $this->eventId)
            ->where('group', $this->group)
            ->where('number', $modality->round_initial)
            ->exists();
        $roundsInOpen = ModelRound::where('modality_id', $this->modalityId)
            ->where('event_id', $this->eventId)
            ->where('group', $this->group)
            ->whereNull('round_status')
            ->exists();

        $this->tableData = [];
        $this->roundFinish = $rounds && !$roundsInOpen;

        if (!$this->roundFinish) {
            // Pré-carrega buffers por número para overlay
            $buffers = RoundBuffer::query()
                ->where('modality_id', $this->modalityId)
                ->where('event_id', $this->eventId)
                ->where('group', $this->group)
                ->get()
                ->keyBy('number');
            foreach ($this->inscriptions as $inscription) {
                foreach ($inscription->participants as $participant) {
                    // Pegar as rodadas para cada inscrição
                    $rounds = ModelRound::where([
                        'inscription_id' => $inscription->id,
                        'participant_id' => $participant->id,
                        'modality_id' => $this->modalityId,
                        'event_id' => $this->eventId,
                        'group' => $this->group
                    ])
                        ->orderBy('number')
                        ->get();

                    // Construir roundsValues e aplicar overlay do buffer
                    $roundsValues = $rounds->pluck('value', 'number')->toArray();
                    foreach ($buffers as $num => $buffer) {
                        $payload = $buffer->payload ?? [];
                        if (isset($payload[$inscription->id][$participant->id])) {
                            $roundsValues[$num] = $payload[$inscription->id][$participant->id];
                        }
                    }
                    $totalHits = collect($roundsValues)->filter(fn($v) => $v === 1)->count();

                    $round_status = '';
                    foreach($rounds as $item){
                        $round_status = $item->round_status;
                    }

                    // Busca força para rodadas classificatórias
                    if($this->group === 'classification') {
                        $roundForce = RoundForce::where([
                            'inscription_id' => $inscription->id,
                            'modality_id' => $this->modalityId,
                            'event_id' => $this->eventId,
                        ])->first();
                    }

                    $this->tableData[$inscription->id][$participant->id] = [
                        'name' => $participant->name,
                        'rounds' => $roundsValues,
                        'total_hits' => $totalHits,
                        'round_status' => $round_status,
                        'modality' => $this->modalityId,
                        'group' => ($this->group === 'classification' && $roundForce) ? $roundForce->force : 'N/C',
                        'inscription_group_name' => $inscription->name,
                    ];
                }
            }
        }
        $this->stepRound = $currentStep;
    }

    public function nextStep($stepIndex): void
    {
        $step = $stepIndex + 2;
        $this->stepRound = $step;
        $this->loadRounds();
    }

    public function previousStep($stepIndex): void
    {
        $this->stepRound = $stepIndex;
        $this->loadRounds();
    }

    // Manipula a mudança de grupo e atualiza os dados
    public function handleGroupChange($data): void
    {
        // Executa a mesma lógica do afterStateUpdate do group
        $this->rounds = collect();
        $this->inscriptions = collect();
        $this->group = $data['state'];

        if ($this->modalityId) {
            $this->updatedModalityId($this->modalityId);
        }
        $this->loadRounds();
        $this->dispatch('reset-wizard');
        $this->data = [];
    }

    // Verifica se existem rodadas pendentes
    private function checkPendingRounds(): void
    {
        $this->pendingRounds = [];

        // Verifica rodadas não finalizadas para cada participante
        foreach ($this->inscriptions as $inscription) {
            foreach ($inscription->participants as $participant) {
                for ($i = 1; $i <= count($this->rounds); $i++) {
                    $round = ModelRound::whereNotNull('round_status')
                        ->whereHas('inscription', function($query) {
                            $query->where('inscription_status', true);
                        })
                        ->where([
                            'inscription_id' => $inscription->id,
                            'participant_id' => $participant->id,
                            'event_id' => $this->eventId,
                            'modality_id' => $this->modalityId,
                            'number' => $i,
                            'group' => $this->group,
                        ])
                        ->first();

                    if (!$round) {
                        $this->pendingRounds[] = [
                            'inscription_id' => $inscription->id,
                            'participant_id' => $participant->id,
                            'round_number' => $i,
                            'participant_name' => $participant->name,
                            'inscription_name' => $inscription->name,
                            'value' => null
                        ];
                    }
                }
            }
        }
    }

    // Salva as rodadas pendentes e finaliza o processo
    public function savePendingRounds($checkPendingRounds = true): void
    {
        foreach ($this->pendingValues as $round => $inscriptions) {
            foreach ($inscriptions as $inscription => $participations) {
                foreach ($participations as $participation => $value) {
                    $roundStatus = (is_null($value)) ? null : 'finish';
                    ModelRound::updateOrCreate([
                        'inscription_id' => $inscription,
                        'participant_id' => $participation,
                        'event_id' => $this->eventId,
                        'modality_id' => $this->modalityId,
                        'number' => $round,
                        'group' => $this->group,
                    ], [
                        'value' => $value,
                        'round_status' => $roundStatus
                    ]);
                }
            }
        }

        // Verifica rodadas pendentes novamente se solicitado
        if ($checkPendingRounds) {
            $this->checkPendingRounds();

            if (!empty($this->pendingRounds)) {
                $this->dispatch('open-modal', id: 'confirmation-modal');
                return;
            }
        }

        // Marca todas rodadas como finalizadas
        ModelRound::where([
            'event_id' => $this->eventId,
            'modality_id' => $this->modalityId,
            'group' => $this->group,
        ])->update(['round_status' => 'finish']);

        Inscription::query()->where([
            'modality_id' => $this->modalityId,
            'event_id' => $this->eventId,
            'inscription_status' => false,
            'lifeless' => true,
            'reborn' => true,
        ])->update(['inscription_value' => 1]);

        $this->dispatch('close-modal', id: 'pending-rounds');
        $this->dispatch('refreshSteps');
        $this->loadRounds();

        Notification::make()
            ->title('Operação realizada com sucesso!')
            ->success()
            ->body('O registro foi salvo corretamente no banco de dados.')
            ->actions([
                Action::make('view')
                    ->label('Ver Resultado Geral')
                    ->url('/admin/results'),
            ])
            ->send();
    }

    // Cancela o processo de finalização
    public function cancelFinalization(): void
    {
        $this->dispatch('close-modal', id: 'confirmation-modal');
    }

    // Finaliza todas as rodadas
    public function finalizeRounds(): void
    {
        $this->cancelFinalization();
        $this->savePendingRounds(checkPendingRounds: false);
    }

    // Cria o formulário para rodadas pendentes
    public function getPendingRoundsForm($index, $round): Form
    {
        return Form::make($this)
            ->schema([
                ToggleButtons::make("pendingValues.{$round['round_number']}.{$round['inscription_id']}.{$round['participant_id']}")
                    ->hiddenLabel()
                    ->inline()
                    ->options([
                        '1' => 'Boa',
                        '0' => 'Branca',
                    ])
                    ->colors([
                        '1' => 'success',
                        '0' => 'danger',
                    ])
                    ->icons([
                        '1' => 'heroicon-o-hand-thumb-up',
                        '0' => 'heroicon-o-hand-thumb-down',
                    ])
                    ->afterStateUpdated(fn ($state) => $this->pendingRounds[$index]['value'] = 1)
            ]);
    }
}
