<?php
namespace App\Http\Controllers\Processamento;

use App\Http\Controllers\Controller;
use App\Models\ContestDate;
use App\Models\QsoResult;
use App\Models\ContestEtapa;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class PontuacaoController extends Controller
{
    // ════════════════════════════════════════════════════════════════════════
    // ETAPA 4 — Claimed Score
    // ════════════════════════════════════════════════════════════════════════

    public function indexClaimed()
    {
        $cid = ContestDate::ativo()?->id;
        return view('processamento.claimed-score', [
            'total_validos' => $cid
                ? QsoResult::where('contest_id',$cid)->where('valid_qso',1)->where('valid_tempqso',1)->where('valid_trocaband','!=',0)->count()
                : QsoResult::where('valid_qso',1)->where('valid_tempqso',1)->where('valid_trocaband','!=',0)->count(),
        ]);
    }

    public function executarClaimed(Request $request)
    {
        $request->validate(
            ['confirmacao' => ['required','in:CONFIRMAR']],
            ['confirmacao.in' => 'Digite exatamente CONFIRMAR (maiúsculas) para prosseguir.']
        );
        session([
            'claimed_status'    => 'processando',
            'claimed_progresso' => [],
            'claimed_total'     => 0,
            'claimed_atual'     => 0,
            'claimed_concluido' => false,
            'claimed_resultado' => null,
        ]);
        return redirect()->route('processamento.claimed-score.progresso');
    }

    public function progressoClaimed()
    {
        if (session('claimed_status') === null) {
            return redirect()->route('processamento.claimed-score')
                             ->with('erro','Inicie o processo pela tela de Claimed Score.');
        }
        return view('processamento.claimed-score-progresso');
    }

    public function statusClaimed()
    {
        return response()->json([
            'status'    => session('claimed_status',    'aguardando'),
            'total'     => session('claimed_total',     0),
            'atual'     => session('claimed_atual',     0),
            'progresso' => session('claimed_progresso', []),
            'concluido' => session('claimed_concluido', false),
            'resultado' => session('claimed_resultado', null),
        ]);
    }

    public function processarClaimed(Request $request)
    {
        if (session('claimed_status') === null) {
            return response()->json(['erro' => 'Sessão não encontrada.'], 403);
        }

        $contest = ContestDate::ativo();
        if (!$contest) {
            return response()->json(['erro' => 'Nenhum contest ativo.'], 422);
        }
        $cid = $contest->id;

        $ini = microtime(true);
        $log = [];

        // ── Fase 1/4: Parser cty.dat ──────────────────────────────────────
        $log[] = ['msg' => 'Fase 1/4 — Carregando cty.dat e construindo mapa de prefixos...', 'tipo' => 'info'];
        $this->salvar('claimed', 4, 0, $log);

        $ctyPath = config('contest.cty_dat');
        if (!file_exists($ctyPath)) {
            $log[] = ['msg' => "❌ Arquivo cty.dat não encontrado em: {$ctyPath}", 'tipo' => 'erro'];
            $this->salvar('claimed', 4, 0, $log);
            return response()->json(['ok' => false]);
        }

        try {
            $prefixMap = $this->buildPrefixMap($this->parseCtyDat($ctyPath));
        } catch (\Throwable $e) {
            $log[] = ['msg' => '❌ Erro ao processar cty.dat: ' . $e->getMessage(), 'tipo' => 'erro'];
            $this->salvar('claimed', 4, 0, $log);
            return response()->json(['ok' => false]);
        }
        $log[] = ['msg' => count($prefixMap) . ' grupos de prefixos carregados.', 'tipo' => 'ok'];

        // ── Fase 2/4: DXCC e Continente ──────────────────────────────────
        $log[] = ['msg' => "Fase 2/4 — Resolvendo DXCC (contest #{$cid})...", 'tipo' => 'info'];
        $this->salvar('claimed', 4, 1, $log);

        $qsos = DB::table('qsos_result')
            ->where('contest_id', $cid)
            ->where('valid_qso', 1)
            ->where('valid_tempqso', 1)
            ->where('valid_trocaband', '!=', 0)
            ->select('id','call_sent','call_rcvd')
            ->get();

        $totalQsos = $qsos->count();
        $log[] = ['msg' => "{$totalQsos} QSOs para processar DXCC.", 'tipo' => 'info'];
        $this->salvar('claimed', 4, 1, $log);

        $semDxcc = 0;
        foreach ($qsos->chunk(200) as $lote) {
            $updates = [];
            foreach ($lote as $q) {
                $sent = $this->buscarDxcc($prefixMap, $q->call_sent);
                $rcvd = $this->buscarDxcc($prefixMap, $q->call_rcvd);
                if (!$sent || !$rcvd) $semDxcc++;
                $updates[] = [
                    'id'             => $q->id,
                    'dxcc_sent'      => $sent['country']   ?? '',
                    'continent_sent' => $sent['continent'] ?? '',
                    'dxcc_rcvd'      => $rcvd['country']   ?? '',
                    'continent_rcvd' => $rcvd['continent'] ?? '',
                ];
            }
            if (!empty($updates)) {
                $cd=''; $ccs=''; $cr=''; $ccr=''; $ids=[];
                foreach ($updates as $u) {
                    $id=$u['id']; $ids[]=$id;
                    $ds=addslashes($u['dxcc_sent']); $cs=addslashes($u['continent_sent']);
                    $dr=addslashes($u['dxcc_rcvd']); $cr_=addslashes($u['continent_rcvd']);
                    $cd.="WHEN {$id} THEN '{$ds}' "; $ccs.="WHEN {$id} THEN '{$cs}' ";
                    $cr.="WHEN {$id} THEN '{$dr}' "; $ccr.="WHEN {$id} THEN '{$cr_}' ";
                }
                $in=implode(',', $ids);
                DB::statement("UPDATE qsos_result SET
                    dxcc_sent=CASE id {$cd} END,
                    continent_sent=CASE id {$ccs} END,
                    dxcc_rcvd=CASE id {$cr} END,
                    continent_rcvd=CASE id {$ccr} END
                    WHERE id IN ({$in})");
            }
        }
        $log[] = ['msg' => "DXCC resolvido." . ($semDxcc > 0 ? " ⚠️ {$semDxcc} sem DXCC." : " Todos resolvidos."), 'tipo' => $semDxcc > 0 ? 'dup' : 'ok'];

        // ── Fase 3/4: Pontos por QSO ─────────────────────────────────────
        $log[] = ['msg' => 'Fase 3/4 — Calculando pontos por QSO...', 'tipo' => 'info'];
        $this->salvar('claimed', 4, 2, $log);

        $pontuacao = [
            '10'=>[1,2,3],'15'=>[1,2,3],'20'=>[1,2,3],
            '40'=>[2,4,6],'80'=>[2,4,6],'160'=>[2,4,6],
        ];

        $qsosPontos = DB::table('qsos_result as q')
            ->join('logs_cabecalhos as l','q.call_sent','=','l.callsign')
            ->where('q.contest_id', $cid)
            ->where('q.valid_qso', 1)->where('q.valid_tempqso', 1)->where('q.valid_trocaband', '!=', 0)
            ->whereColumn('q.category_band','l.category_band')
            ->select('q.id','q.band','q.dxcc_sent','q.dxcc_rcvd','q.continent_sent','q.continent_rcvd')
            ->get();

        $porPonto = [];
        foreach ($qsosPontos as $q) {
            $band = strtolower($q->band);
            $pts  = $pontuacao[$band] ?? null;
            if (!$pts) continue;
            if ($q->dxcc_sent === $q->dxcc_rcvd)              $p = $pts[0];
            elseif ($q->continent_sent === $q->continent_rcvd) $p = $pts[1];
            else                                               $p = $pts[2];
            $porPonto[$p][] = $q->id;
        }
        foreach ($porPonto as $pts => $ids) {
            foreach (array_chunk($ids, 2000) as $lote) {
                DB::table('qsos_result')->whereIn('id', $lote)->update(['pontos_qso' => $pts]);
            }
        }
        $log[] = ['msg' => $qsosPontos->count() . ' QSOs pontuados.', 'tipo' => 'ok'];

        // ── Fase 4/4: Multiplicadores e Claimed Score ─────────────────────
        $log[] = ['msg' => 'Fase 4/4 — Calculando multiplicadores e Claimed Score...', 'tipo' => 'info'];
        $this->salvar('claimed', 4, 3, $log);

        $qsosMult = DB::table('qsos_result as q')
            ->join('logs_cabecalhos as l','q.call_sent','=','l.callsign')
            ->where('q.contest_id', $cid)
            ->where('q.valid_qso', 1)->where('q.valid_tempqso', 1)->where('q.valid_trocaband', '!=', 0)
            ->whereColumn('q.category_band','l.category_band')
            ->select('q.id','q.call_sent','q.band','q.exch_rcvd','q.dxcc_rcvd')
            ->orderBy('q.call_sent')->orderBy('q.band')->orderBy('q.exch_rcvd')->orderBy('q.dxcc_rcvd')
            ->get();

        $prevBand=null; $prevExch=null; $prevDxcc=null; $prevCall=null;
        $multUpdates=[];
        foreach ($qsosMult as $q) {
            if ($q->call_sent !== $prevCall) {
                $prevCall=$q->call_sent; $prevBand=$prevExch=$prevDxcc=null;
            }
            $m1=($q->band!==$prevBand||$q->exch_rcvd!==$prevExch)?1:0;
            $m2=($q->band!==$prevBand||$q->dxcc_rcvd!==$prevDxcc)?1:0;
            $m3=($q->exch_rcvd==='HQ')?1:0;
            $multUpdates[]=['id'=>$q->id,'multi_um'=>$m1,'multi_dois'=>$m2,'multi_tres'=>$m3];
            $prevBand=$q->band; $prevExch=$q->exch_rcvd; $prevDxcc=$q->dxcc_rcvd;
        }
        foreach (array_chunk($multUpdates,2000) as $chunk) {
            foreach ($chunk as $u) {
                DB::table('qsos_result')->where('id',$u['id'])
                    ->update(['multi_um'=>$u['multi_um'],'multi_dois'=>$u['multi_dois'],'multi_tres'=>$u['multi_tres']]);
            }
        }

        $qsosClaimed = DB::table('qsos_result as q')
            ->join('logs_cabecalhos as l','q.call_sent','=','l.callsign')
            ->where('q.contest_id', $cid)
            ->where('q.valid_qso',1)->where('q.valid_tempqso',1)->where('q.valid_trocaband','!=',0)
            ->whereColumn('q.category_band','l.category_band')
            ->select('q.call_sent','l.claimed_score',
                DB::raw('SUM(q.pontos_qso) as soma_pontos'),
                DB::raw('SUM(q.multi_um)   as soma_m1'),
                DB::raw('SUM(q.multi_dois) as soma_m2'),
                DB::raw('SUM(q.multi_tres) as soma_m3'))
            ->groupBy('q.call_sent','l.claimed_score')->get();

        $resumo=[]; $grandTotal=0;
        foreach ($qsosClaimed as $r) {
            $totalMult=$r->soma_m1+$r->soma_m2+$r->soma_m3;
            $claimed=$totalMult>0?$r->soma_pontos*$totalMult:$r->soma_pontos;
            $grandTotal+=$claimed;
            $resumo[]=['callsign'=>$r->call_sent,'pontos'=>(int)$r->soma_pontos,
                       'total_multi'=>$totalMult,'claimed'=>$claimed,'claimed_informado'=>(int)($r->claimed_score??0)];
            DB::table('logs_cabecalhos')->where('callsign',$r->call_sent)
                ->where('contest_id',$cid)->update(['claimed_calculado'=>$claimed]);
            $log[]=['msg'=>"✓ {$r->call_sent} — Pts: {$r->soma_pontos} × Multi: {$totalMult} = {$claimed}",'tipo'=>'ok'];
        }
        $this->salvar('claimed',4,4,$log);

        $fim=microtime(true); $seg=$fim-$ini;
        $tempo=$seg>=60?number_format($seg/60,2).' min':number_format($seg,1).' seg';

        ContestEtapa::concluir('4',['total_processados'=>$totalQsos,'total_validos'=>count($resumo),'tempo_gasto'=>$tempo]);
        activity()->causedBy(auth()->user())->log("Etapa 4: {$totalQsos} QSOs, Grand Total {$grandTotal} (contest #{$cid}).");

        session()->put('claimed_status',    'concluido');
        session()->put('claimed_total',     4);
        session()->put('claimed_atual',     4);
        session()->put('claimed_progresso', [['msg'=>"Concluido em {$tempo} | Grand Total: ".number_format($grandTotal),'tipo'=>'ok']]);
        session()->put('claimed_concluido', true);
        session()->put('claimed_resultado', [
            'total_qsos'=>$totalQsos,'total_ops'=>count($resumo),'grand_total'=>$grandTotal,
            'resumo'=>$resumo,'sem_dxcc'=>$semDxcc,'tempo'=>$tempo,
            'inicio'=>date('d/m/Y H:i:s',(int)$ini),'fim'=>date('d/m/Y H:i:s',(int)$fim),
        ]);
        session()->save();
        return response()->json(['ok' => true]);
    }

    // ════════════════════════════════════════════════════════════════════════
    // ETAPA 7 — Calcular Pontos QSO (pós-confirmação)
    // ════════════════════════════════════════════════════════════════════════

    public function indexPontos()
    {
        $cid = ContestDate::ativo()?->id;
        return view('processamento.pontuar', [
            'confirmados' => $cid
                ? QsoResult::where('contest_id',$cid)->where('confirmado',1)->count()
                : QsoResult::where('confirmado',1)->count(),
        ]);
    }

    public function executarPontos(Request $request)
    {
        $request->validate(
            ['confirmacao' => ['required','in:CONFIRMAR']],
            ['confirmacao.in' => 'Digite exatamente CONFIRMAR (maiusculas) para prosseguir.']
        );
        session([
            'pontos_status'    => 'processando',
            'pontos_progresso' => [],
            'pontos_total'     => 0,
            'pontos_atual'     => 0,
            'pontos_concluido' => false,
            'pontos_resultado' => null,
        ]);
        return redirect()->route('processamento.pontuar.progresso');
    }

    public function progressoPontos()
    {
        if (session('pontos_status') === null) {
            return redirect()->route('processamento.pontuar')
                             ->with('erro','Inicie o processo pela tela de Calcular Pontos.');
        }
        return view('processamento.pontuar-progresso');
    }

    public function statusPontos()
    {
        return response()->json([
            'status'    => session('pontos_status',    'aguardando'),
            'total'     => session('pontos_total',     0),
            'atual'     => session('pontos_atual',     0),
            'progresso' => session('pontos_progresso', []),
            'concluido' => session('pontos_concluido', false),
            'resultado' => session('pontos_resultado', null),
        ]);
    }

    public function processarPontos(Request $request)
    {
        if (session('pontos_status') === null) {
            return response()->json(['erro' => 'Sessao nao encontrada.'], 403);
        }

        $contest = ContestDate::ativo();
        if (!$contest) {
            return response()->json(['erro' => 'Nenhum contest ativo.'], 422);
        }
        $cid = $contest->id;

        $ini = microtime(true);
        $log = [];

        $salvar = function(int $fase, int $total, array $log) {
            session()->put('pontos_status',    'processando');
            session()->put('pontos_atual',     $fase);
            session()->put('pontos_total',     $total);
            session()->put('pontos_progresso', array_slice($log, -30));
            session()->save();
        };

        $pontuacao = [
            '10'=>[1,2,3],'10m'=>[1,2,3],'15'=>[1,2,3],'15m'=>[1,2,3],
            '20'=>[1,2,3],'20m'=>[1,2,3],'40'=>[2,4,6],'40m'=>[2,4,6],
            '80'=>[2,4,6],'80m'=>[2,4,6],'160'=>[2,4,6],'160m'=>[2,4,6],
        ];

        // ── Fase 1/3: Calcular pontos por QSO ────────────────────────────
        $log[] = ['msg' => "Fase 1/3 — Calculando pontos (contest #{$cid})...", 'tipo' => 'info'];
        $salvar(0, 3, $log);

        // Zera QSOs fora de categoria de banda
        $zerados = DB::table('qsos_result as q')
            ->join('logs_cabecalhos as l', 'q.call_sent', '=', 'l.callsign')
            ->where('q.contest_id', $cid)
            ->where('q.confirmado', 1)
            ->whereRaw("q.category_band != 'ALL'")
            ->whereRaw("CONCAT(q.band,'M') != l.category_band")
            ->pluck('q.id')->toArray();
        if (!empty($zerados)) {
            foreach (array_chunk($zerados, 2000) as $lote) {
                DB::table('qsos_result')->whereIn('id', $lote)
                    ->update(['pontos_qso'=>0,'multi_um'=>0,'multi_dois'=>0,'multi_tres'=>0]);
            }
            $log[] = ['msg' => count($zerados).' QSOs zerados (banda fora da categoria).', 'tipo' => 'dup'];
        }

        $qsos = DB::table('qsos_result as q')
            ->join('logs_cabecalhos as l', 'q.call_sent', '=', 'l.callsign')
            ->where('q.contest_id', $cid)
            ->where('q.confirmado', 1)
            ->select('q.id','q.band','q.category_band','l.category_band as cat_band_log',
                     'q.dxcc_sent','q.dxcc_rcvd','q.continent_sent','q.continent_rcvd','q.call_sent',
                     'q.exch_rcvd','q.dxcc_rcvd')
            ->orderBy('q.call_sent')->get();

        $total       = $qsos->count();
        $porOperador = $qsos->groupBy('call_sent');
        $totalOps    = $porOperador->count();
        $salvar(0, 3, $log);

        $log[] = ['msg' => "{$total} QSOs confirmados | {$totalOps} operadores.", 'tipo' => 'info'];
        $salvar(0, 3, $log);

        $totalPontos = 0; $totalValidos = 0; $resumoPorOp = [];

        foreach ($porOperador as $callSent => $qsosOp) {
            $idx  = count($resumoPorOp); $atual = $idx + 1;
            if ($idx % 10 === 0) {
                $log[] = ['msg' => "→ [{$atual}/{$totalOps}] {$callSent}", 'tipo' => 'arq'];
                $salvar(0, 3, array_slice($log, -20));
            }

            $pontosOp = 0; $updates = [];

            foreach ($qsosOp as $q) {
                $catBand = strtolower(trim($q->category_band));
                $band    = strtolower(trim($q->band));
                $chave   = $catBand === 'all' ? $band : $band.'m';

                if ($catBand !== 'all' && $chave !== $catBand) {
                    $updates[] = ['id'=>$q->id,'pontos'=>0]; continue;
                }

                $pts = $pontuacao[$chave] ?? null;
                if (!$pts) { $updates[] = ['id'=>$q->id,'pontos'=>0]; continue; }

                if ($q->dxcc_sent === $q->dxcc_rcvd)              $pontos = $pts[0];
                elseif ($q->continent_sent === $q->continent_rcvd) $pontos = $pts[1];
                else                                               $pontos = $pts[2];

                $updates[] = ['id'=>$q->id,'pontos'=>$pontos];
                $pontosOp += $pontos; $totalValidos++;
            }

            $porPontos = [];
            foreach ($updates as $u) { $porPontos[$u['pontos']][] = $u['id']; }
            foreach ($porPontos as $pts => $ids) {
                foreach (array_chunk($ids, 2000) as $lote) {
                    DB::table('qsos_result')->whereIn('id', $lote)->update(['pontos_qso'=>$pts]);
                }
            }

            $totalPontos += $pontosOp;
            $resumoPorOp[]=['callsign'=>$callSent,'qsos'=>$qsosOp->count(),'pontos'=>$pontosOp,
                            'multi_um'=>0,'multi_dois'=>0,'multi_tres'=>0,'final_score'=>0];
        }

        $log[] = ['msg' => "✅ {$totalValidos} QSOs pontuados | {$totalPontos} pontos.", 'tipo' => 'ok'];
        $salvar(1, 3, $log);

        // ── Fase 2/3: Multiplicadores ─────────────────────────────────────
        $log[] = ['msg' => 'Fase 2/3 — Calculando multiplicadores...', 'tipo' => 'info'];
        $salvar(1, 3, $log);

        $qsosMult = DB::table('qsos_result')
            ->where('contest_id', $cid)
            ->where('confirmado', 1)
            ->orderBy('call_sent')->orderBy('band')->orderBy('exch_rcvd')->orderBy('dxcc_rcvd')
            ->select('id','call_sent','band','exch_rcvd','dxcc_rcvd')->get();

        $prevCall=null; $prevBand=null; $prevExch=null; $prevDxcc=null; $multData=[];

        foreach ($qsosMult as $q) {
            if ($q->call_sent!==$prevCall) {
                $prevCall=$q->call_sent; $prevBand=$prevExch=$prevDxcc=null;
            }
            $m1=($q->band!==$prevBand||$q->exch_rcvd!==$prevExch)?1:0;
            $m2=($q->band!==$prevBand||$q->dxcc_rcvd!==$prevDxcc)?1:0;
            $m3=(strtoupper(trim($q->exch_rcvd))==='HQ')?1:0;
            $multData[]=['id'=>$q->id,'call'=>$q->call_sent,'m1'=>$m1,'m2'=>$m2,'m3'=>$m3];
            $prevBand=$q->band; $prevExch=$q->exch_rcvd; $prevDxcc=$q->dxcc_rcvd;
        }

        foreach (array_chunk($multData, 1000) as $lote) {
            $c1=$c2=$c3=''; $ids=[];
            foreach ($lote as $u) {
                $c1.="WHEN {$u['id']} THEN {$u['m1']} ";
                $c2.="WHEN {$u['id']} THEN {$u['m2']} ";
                $c3.="WHEN {$u['id']} THEN {$u['m3']} ";
                $ids[]=$u['id'];
            }
            $in=implode(',', $ids);
            DB::statement("UPDATE qsos_result SET
                multi_um   = CASE id {$c1} END,
                multi_dois = CASE id {$c2} END,
                multi_tres = CASE id {$c3} END
                WHERE id IN ({$in})");
        }

        $log[] = ['msg' => count($multData).' QSOs com multiplicadores calculados.', 'tipo' => 'ok'];
        $salvar(2, 3, $log);

        // ── Fase 3/3: Final Score ─────────────────────────────────────────
        $log[] = ['msg' => 'Fase 3/3 — Calculando Final Score por operador...', 'tipo' => 'info'];
        $salvar(2, 3, array_slice($log, -10));

        $totais = DB::table('qsos_result')
            ->where('contest_id', $cid)
            ->where('confirmado', 1)
            ->select('call_sent',
                DB::raw('SUM(pontos_qso) as soma_pontos'),
                DB::raw('SUM(multi_um)   as soma_m1'),
                DB::raw('SUM(multi_dois) as soma_m2'),
                DB::raw('SUM(multi_tres) as soma_m3'))
            ->groupBy('call_sent')->get();

        $grandTotal=0; $resumoFinal=[];

        foreach ($totais as $r) {
            $totalMult=$r->soma_m1+$r->soma_m2+$r->soma_m3;
            $finalScore=$totalMult>0?(int)$r->soma_pontos*$totalMult:(int)$r->soma_pontos;
            $grandTotal+=$finalScore;
            $resumoFinal[]=['callsign'=>$r->call_sent,'pontos'=>(int)$r->soma_pontos,
                            'multi_um'=>(int)$r->soma_m1,'multi_dois'=>(int)$r->soma_m2,
                            'multi_tres'=>(int)$r->soma_m3,'total_multi'=>$totalMult,'final_score'=>$finalScore];
            DB::table('logs_cabecalhos')
                ->where('callsign',$r->call_sent)->where('contest_id',$cid)
                ->update(['final_score'=>$finalScore]);
        }

        $fim=microtime(true); $seg=$fim-$ini;
        $tempo=$seg>=60?number_format($seg/60,2).' min':number_format($seg,1).' seg';

        ContestEtapa::concluir('7',['total_processados'=>$total,'total_validos'=>count($resumoFinal),'tempo_gasto'=>$tempo]);
        activity()->causedBy(auth()->user())->log("Etapa 7: {$total} QSOs, grand total {$grandTotal} (contest #{$cid}).");

        session()->put('pontos_status',    'concluido');
        session()->put('pontos_total',     3);
        session()->put('pontos_atual',     3);
        session()->put('pontos_progresso', [['msg'=>"Concluido em {$tempo} | Grand Total: ".number_format($grandTotal),'tipo'=>'ok']]);
        session()->put('pontos_concluido', true);
        session()->put('pontos_resultado', [
            'total_qsos'=>$total,'total_ops'=>count($resumoFinal),'grand_total'=>$grandTotal,
            'zero_pontos'=>count($zerados),'resumo'=>array_slice($resumoFinal,0,200),
            'tempo'=>$tempo,'inicio'=>date('d/m/Y H:i:s',(int)$ini),'fim'=>date('d/m/Y H:i:s',(int)$fim),
        ]);
        session()->save();
        return response()->json(['ok' => true]);
    }

    public function indexMulti()
    {
        $cid = ContestDate::ativo()?->id;
        return view('processamento.pontuar', [
            'confirmados' => $cid
                ? QsoResult::where('contest_id',$cid)->where('confirmado',1)->count()
                : QsoResult::where('confirmado',1)->count(),
        ]);
    }

    public function executarMulti(Request $request)
    {
        activity()->causedBy(auth()->user())->log('Etapa 8: Multiplicadores executado.');
        return redirect()->route('dashboard')
            ->with('sucesso', 'Etapa 8 concluída — multiplicadores calculados pelo sistema Laravel (Etapa 7).');
    }

    // ════════════════════════════════════════════════════════════════════════
    // HELPERS
    // ════════════════════════════════════════════════════════════════════════

    private function salvar(string $prefix, int $total, int $atual, array $log): void
    {
        session([
            "{$prefix}_status"    => 'processando',
            "{$prefix}_total"     => $total,
            "{$prefix}_atual"     => $atual,
            "{$prefix}_progresso" => $log,
        ]);
        session()->save();
    }

    private function parseCtyDat(string $filePath): array
    {
        $result=[]; $currentCountry=null; $prefixBuffer='';
        $lines=file($filePath,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
        foreach ($lines as $line) {
            $line=trim($line);
            if ($line===''||$line[0]===';') continue;
            if (substr($line,-1)===':') {
                if ($currentCountry!==null&&$prefixBuffer!=='') {
                    $currentCountry['prefixes']=$this->cleanPrefixes($prefixBuffer);
                    $result[]=$currentCountry; $prefixBuffer='';
                }
                $parts=explode(':',$line);
                $currentCountry=['country'=>trim($parts[0]),'continent'=>trim($parts[3]??''),'prefixes'=>[]];
            } else {
                $prefixBuffer.=' '.$line;
                if (str_contains($line,';')) {
                    if ($currentCountry!==null) {
                        $currentCountry['prefixes']=$this->cleanPrefixes($prefixBuffer);
                        $result[]=$currentCountry; $currentCountry=null;
                    }
                    $prefixBuffer='';
                }
            }
        }
        if ($currentCountry!==null&&$prefixBuffer!=='') {
            $currentCountry['prefixes']=$this->cleanPrefixes($prefixBuffer);
            $result[]=$currentCountry;
        }
        return $result;
    }

    private function cleanPrefixes(string $buffer): array
    {
        $prefixes=explode(',',$buffer); $clean=[];
        foreach ($prefixes as $raw) {
            $p=strtoupper(trim($raw)); $p=ltrim($p,'=');
            $p=preg_replace('/\{.*?\}|\[.*?\]|\(.*?\)/','', $p);
            $p=preg_replace('/[={}()\[\]]/','', $p);
            $p=trim($p,",; \t\n\r");
            if ($p!=='') $clean[]=$p;
        }
        return array_values(array_unique($clean));
    }

    private function buildPrefixMap(array $countries): array
    {
        $map=[];
        foreach ($countries as $country) {
            foreach ($country['prefixes'] as $prefix) {
                $prefix=strtoupper(trim($prefix));
                $len=strlen($prefix);
                if ($prefix!=='') $map[$len][$prefix]=$country;
            }
        }
        krsort($map);
        return $map;
    }

    private function buscarDxcc(array $prefixMap, string $callsign): ?array
    {
        $callsign=strtoupper(trim($callsign));
        foreach ($prefixMap as $len => $prefixes) {
            $sub=substr($callsign,0,$len);
            if (isset($prefixes[$sub])) return $prefixes[$sub];
        }
        return null;
    }
}
