<?php

namespace App\Filament\Pages;

use App\Models\Event;
use App\Models\Inscription;
use App\Models\Modality;
use App\Models\ParticipantScore;
use App\Models\Round as ModelRound;
use App\Models\RoundForce;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Set;
use Filament\Pages\Concerns\InteractsWithFormActions;
use Filament\Pages\Page;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;

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

    protected static ?string $navigationIcon = 'heroicon-o-clipboard';
    protected static ?string $navigationLabel = 'Resultados';
    protected static ?string $slug = 'results';
    protected static ?string $navigationGroup = 'Provas';
    protected static ?string $title = 'Resultados';
    protected static string $view = 'filament.pages.result';

    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;
    public bool $without_participants = false;

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

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

                Select::make('modalityId')
                    ->label('Selecione a modalidade')
                    ->selectablePlaceholder(false)
                    ->options(fn () => $this->eventId
                        ? Event::find($this->eventId)?->modalities()->select('modalities.id', 'modalities.name')->orderBy('modalities.created_at', 'desc')->pluck('name', 'id') ?? []
                        : [])
                    ->live()
                    ->reactive()
                    ->visible(fn () => filled($this->eventId))
                    ->afterStateUpdated(function ($state, Set $set) {
                        $this->updatedModalityId($state, true);
                        $this->loadRounds();
                    })
                    ->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)
                    ->nullable()
                    ->live()
                    ->afterStateUpdated(function ($state) {
                        // Limpa os dados atuais
                        $this->rounds = collect();
                        $this->inscriptions = collect();
                        $this->group = $state ?? '';

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

                        // Se tiver uma modalidade selecionada, recarrega tudo
                        if ($this->modalityId) {
                            $this->updatedModalityId($this->modalityId);
                        }
                        $this->loadRounds();
                    }),
            ])
            ->columns($this->hasClassificationRounds ? 3 : 2),
        ];
    }

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

        // Seleciona primeiro modalityId disponível
        $firstModality = Event::find($eventId)?->modalities->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): void
    {
        $modality = Modality::find($modalityId);
        if (!$modality) { return; }
        $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
        ])->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
            ])->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 = '';
            }
        }
    }

    protected function getRedirectUrl(): string
    {
        return $this->getResource()::getUrl('index');
    }

    protected function initializePolling(): void
    {
        $this->dispatch('poll-start');
    }

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

    //Carrega as informações necessárias para a exibição na tabela dos resultados
    public function loadRounds(): void
    {
        $this->tableData = [];
        $this->updatedModalityId($this->modalityId);
        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();

                $totalHits = $rounds->where('value', 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' => $rounds->pluck('value', 'number')->toArray(),
                    'total_hits' => $totalHits,
                    'round_status' => $round_status,
                    'modality' => $this->modalityId,
                    'group' => ($this->group === 'classification' && $roundForce) ? $roundForce->force : 'N/C',
                    'inscription_group_name' => $inscription->name,
                ];

                // Ordena a tabela de pontuação pelo total de acertos em ordem decrescente (maior pontuação primeiro)
                uasort($this->tableData, function ($a, $b) {
                    foreach ($a as $participantData) {
                        $aHits = $participantData['total_hits'];
                        foreach ($b as $bParticipantData) {
                            $bHits = $bParticipantData['total_hits'];
                            return $bHits <=> $aHits;
                        }
                    }
                });

                $this->updateParticipantScore($inscription->id, $totalHits);
            }


        }
    }

    //Atualiza a quantidade de acertos do participante na modalidade do evento
    public function updateParticipantScore(int $inscriptionId, int $totalHits): void
    {
        ParticipantScore::updateOrCreate([
            'inscription_id' => $inscriptionId,
            'event_id' => $this->eventId,
            'modality_id' => $this->modalityId,
            'group' => $this->group
        ], ['total_hits' => $totalHits]);
    }

    // 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 = [];
    }
}
