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

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

class ResultadoController extends Controller
{
    // ════════════════════════════════════════════════════════════════════════
    // ETAPA 9 — Final Score / Resultado por Categoria
    // ════════════════════════════════════════════════════════════════════════

    public function indexFinal()
    {
        $cid = ContestDate::ativo()?->id;
        return view('processamento.final-score', [
            'total_confirmados' => $cid
                ? QsoResult::where('contest_id',$cid)->where('confirmado',1)->count()
                : QsoResult::where('confirmado',1)->count(),
            'total_categorias'  => $cid
                ? DB::table('qsos_result')->where('contest_id',$cid)->where('confirmado',1)->distinct()->count('categoria_participante')
                : DB::table('qsos_result')->where('confirmado',1)->distinct()->count('categoria_participante'),
        ]);
    }

    public function executarFinal(Request $request)
    {
        $request->validate(
            ['confirmacao' => ['required','in:CONFIRMAR']],
            ['confirmacao.in' => 'Digite exatamente CONFIRMAR (maiusculas) para prosseguir.']
        );
        session([
            'final_status'    => 'processando',
            'final_progresso' => [],
            'final_total'     => 3,
            'final_atual'     => 0,
            'final_concluido' => false,
            'final_resultado' => null,
        ]);
        return redirect()->route('processamento.final-score.progresso');
    }

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

    public function statusFinal()
    {
        return response()->json([
            'status'    => session('final_status',    'aguardando'),
            'total'     => session('final_total',     3),
            'atual'     => session('final_atual',     0),
            'progresso' => session('final_progresso', []),
            'concluido' => session('final_concluido', false),
            'resultado' => session('final_resultado', null),
        ]);
    }

    public function processarFinal(Request $request)
    {
        if (session('final_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, array $log) {
            session()->put('final_status',    'processando');
            session()->put('final_atual',     $fase);
            session()->put('final_progresso', array_slice($log, -30));
            session()->save();
        };

        // Fase 1/3: Limpar APENAS o contest ativo — preserva outros anos
        $log[] = ['msg' => "Fase 1/3 — Limpando resultados_final do contest #{$cid}...", 'tipo' => 'info'];
        $salvar(0, $log);

        DB::table('resultados_final')->where('contest_id', $cid)->delete();
        $log[] = ['msg' => "resultados_final do contest #{$cid} limpo.", 'tipo' => 'ok'];

        // Fase 2/3: Calcular ranking por categoria (filtrado pelo contest ativo)
        $log[] = ['msg' => 'Fase 2/3 — Calculando ranking por categoria...', 'tipo' => 'info'];
        $salvar(1, $log);

        $resultados = DB::select("
            SELECT
                qr.contest_id,
                qr.categoria_participante,
                qr.call_sent,
                SUM(qr.confirmado)    AS total_qsos,
                SUM(qr.pontos_qso)    AS total_pontos,
                SUM(qr.multi_um)      AS total_multi_um,
                SUM(qr.multi_dois)    AS total_multi_dois,
                SUM(qr.multi_tres)    AS total_multi_tres,
                ANY_VALUE(qr.club)    AS club,
                ANY_VALUE(lc.name)    AS nome,
                ANY_VALUE(lc.email)   AS email,
                ANY_VALUE(lc.address) AS address,
                ANY_VALUE(lc.address_city)           AS address_city,
                ANY_VALUE(lc.address_state_province) AS address_state_province,
                ANY_VALUE(lc.address_postalcode)     AS address_postalcode,
                ANY_VALUE(lc.address_country)        AS address_country,
                ANY_VALUE(lc.claimed_score)          AS claimed_informado,
                ANY_VALUE(lc.claimed_calculado)      AS claimed_calculado,
                (CASE
                    WHEN ANY_VALUE(lc.claimed_calculado) > 0
                    THEN 100 - (((SUM(qr.pontos_qso) *
                         (CASE WHEN (SUM(qr.multi_um)+SUM(qr.multi_dois)+SUM(qr.multi_tres)) > 0
                               THEN (SUM(qr.multi_um)+SUM(qr.multi_dois)+SUM(qr.multi_tres))
                               ELSE 1 END)
                    ) / ANY_VALUE(lc.claimed_calculado)) * 100)
                    ELSE NULL
                END) AS reducao,
                (SUM(qr.pontos_qso) *
                    (CASE
                        WHEN (SUM(qr.multi_um)+SUM(qr.multi_dois)+SUM(qr.multi_tres)) > 0
                        THEN (SUM(qr.multi_um)+SUM(qr.multi_dois)+SUM(qr.multi_tres))
                        ELSE 1
                    END)
                ) AS final_score
            FROM qsos_result qr
            LEFT JOIN logs_cabecalhos lc
                ON UPPER(TRIM(qr.call_sent)) = UPPER(TRIM(lc.callsign))
                AND lc.contest_id = {$cid}
            WHERE qr.confirmado = 1
              AND qr.contest_id = {$cid}
            GROUP BY qr.categoria_participante, qr.call_sent, qr.club, qr.contest_id
            ORDER BY qr.categoria_participante ASC, final_score DESC
        ");

        $total      = count($resultados);
        $totalCatsQ = DB::table('qsos_result')->where('contest_id',$cid)->where('confirmado',1)->distinct()->count('categoria_participante');
        $log[] = ['msg' => "{$total} operadores em {$totalCatsQ} categorias.", 'tipo' => 'info'];
        $salvar(1, $log);

        // Fase 3/3: Inserir com ranking
        $log[] = ['msg' => 'Fase 3/3 — Inserindo em resultados_final com ranking...', 'tipo' => 'info'];
        $salvar(2, $log);

        $categoriaAtual = null; $rank = 0; $totalCats = 0; $catOps = 0; $catScore = 0; $resumoCats = [];

        foreach ($resultados as $r) {
            if ($r->categoria_participante !== $categoriaAtual) {
                if ($categoriaAtual !== null) {
                    $resumoCats[] = ['categoria'=>$categoriaAtual,'operadores'=>$catOps,'total_score'=>$catScore];
                    $log[] = ['msg' => "OK {$categoriaAtual} — {$catOps} op. | ".number_format($catScore), 'tipo' => 'ok'];
                    $salvar(2, $log);
                }
                $categoriaAtual = $r->categoria_participante;
                $rank = 0; $catOps = 0; $catScore = 0; $totalCats++;
            }
            $rank++; $catOps++; $catScore += $r->final_score;

            DB::table('resultados_final')->insert([
                'contest_id'             => $r->contest_id,
                'categoria'              => $r->categoria_participante,
                'rk'                     => $rank,
                'callsign'               => $r->call_sent,
                'nome'                   => mb_substr((string)($r->nome ?? ''), 0, 30),
                'total_qsos_validos'     => $r->total_qsos,
                'total_pontos'           => $r->total_pontos,
                'total_multi_um'         => $r->total_multi_um,
                'total_multi_dois'       => $r->total_multi_dois,
                'total_multi_tres'       => $r->total_multi_tres,
                'claimed_informado'      => $r->claimed_informado,
                'claimed_calculado'      => $r->claimed_calculado,
                'final_score'            => $r->final_score,
                'percentual_reducao'     => $r->reducao,
                'club'                   => $r->club,
                'address'                => $r->address,
                'address_city'           => $r->address_city,
                'address_state_province' => $r->address_state_province,
                'address_postalcode'     => $r->address_postalcode,
                'address_country'        => $r->address_country,
                'email'                  => $r->email,
            ]);
        }

        if ($categoriaAtual !== null) {
            $resumoCats[] = ['categoria'=>$categoriaAtual,'operadores'=>$catOps,'total_score'=>$catScore];
            $log[] = ['msg' => "OK {$categoriaAtual} — {$catOps} op. | ".number_format($catScore), 'tipo' => 'ok'];
        }

        $fim=microtime(true); $seg=$fim-$ini;
        $tempo=$seg>=60?number_format($seg/60,2).' min':number_format($seg,1).' seg';
        $log[] = ['msg' => "Concluido em {$tempo} | {$total} operadores em {$totalCats} categorias.", 'tipo' => 'ok'];

        ContestEtapa::concluir('8',['total_processados'=>$total,'total_validos'=>$totalCats,'tempo_gasto'=>$tempo]);
        activity()->causedBy(auth()->user())
                  ->log("Etapa 9: {$total} operadores em {$totalCats} categorias (contest #{$cid}).");

        session()->put('final_status',    'concluido');
        session()->put('final_total',     3);
        session()->put('final_atual',     3);
        session()->put('final_progresso', array_slice($log, -30));
        session()->put('final_concluido', true);
        session()->put('final_resultado', [
            'total_ops'=>$total,'total_cats'=>$totalCats,'resumo_cats'=>$resumoCats,
            '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 10 — Resultado Final (Ranking publicável)
    // ════════════════════════════════════════════════════════════════════════

    public function indexResultado()
    {
        $cid = ContestDate::ativo()?->id;
        $q   = $cid ? DB::table('resultados_final')->where('contest_id',$cid) : DB::table('resultados_final');
        return view('processamento.resultado', [
            'totalResultados' => (clone $q)->count(),
            'totalCategorias' => (clone $q)->distinct()->count('categoria'),
            'grandTotal'      => (clone $q)->sum('final_score'),
        ]);
    }

    public function executarResultado(Request $request)
    {
        $request->validate(
            ['confirmacao' => ['required','in:CONFIRMAR']],
            ['confirmacao.in' => 'Digite exatamente CONFIRMAR (maiusculas).']
        );
        session([
            'resultado_status'    => 'processando',
            'resultado_progresso' => [],
            'resultado_total'     => 2,
            'resultado_atual'     => 0,
            'resultado_concluido' => false,
            'resultado_resultado' => null,
        ]);
        return redirect()->route('processamento.resultado.progresso');
    }

    public function progressoResultado()
    {
        if (session('resultado_status') === null) {
            return redirect()->route('processamento.resultado')
                             ->with('erro', 'Inicie pela tela de Resultado Final.');
        }
        return view('processamento.resultado-progresso');
    }

    public function statusResultado()
    {
        return response()->json([
            'status'    => session('resultado_status',    'aguardando'),
            'total'     => session('resultado_total',     2),
            'atual'     => session('resultado_atual',     0),
            'progresso' => session('resultado_progresso', []),
            'concluido' => session('resultado_concluido', false),
            'resultado' => session('resultado_resultado', null),
        ]);
    }

    public function processarResultado(Request $request)
    {
        if (session('resultado_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, array $log) {
            session()->put('resultado_status',    'processando');
            session()->put('resultado_atual',     $fase);
            session()->put('resultado_progresso', array_slice($log, -30));
            session()->save();
        };

        // Fase 1/2: Atualizar category_id (apenas contest ativo)
        $log[] = ['msg' => "Fase 1/2 — Atualizando category_id (contest #{$cid})...", 'tipo' => 'info'];
        $salvar(0, $log);

        DB::statement('SET SQL_SAFE_UPDATES = 0');
        $affected = DB::update("
            UPDATE resultados_final rf
            JOIN categorias c ON rf.categoria = c.concatenado
            SET rf.category_id = c.Id
            WHERE rf.contest_id = {$cid}
        ");
        DB::statement('SET SQL_SAFE_UPDATES = 1');

        $log[] = ['msg' => "{$affected} registros com category_id atualizado.", 'tipo' => 'ok'];
        $salvar(1, $log);

        // Fase 2/2: Gerar resumo (apenas contest ativo)
        $log[] = ['msg' => 'Fase 2/2 — Compilando resultado por categoria...', 'tipo' => 'info'];
        $salvar(1, $log);

        $porCategoria = DB::table('resultados_final')
            ->where('contest_id', $cid)
            ->orderBy('categoria')->orderBy('rk')->get();

        $grandTotal=0; $catAtual=null; $catBuffer=[]; $resumoCats=[]; $lideres=[];

        foreach ($porCategoria as $r) {
            if ($r->categoria !== $catAtual) {
                if ($catAtual !== null) { $resumoCats[] = $this->buildCatResumo($catAtual, $catBuffer); }
                $catAtual=$r->categoria; $catBuffer=[];
            }
            $catBuffer[]  = $r;
            $grandTotal  += $r->final_score;

            if ($r->rk == 1 && stripos($r->categoria, 'CHECKLOG') === false) {
                $lideres[] = [
                    'categoria'   => $r->categoria,
                    'callsign'    => $r->callsign,
                    'nome'        => strtoupper($r->nome ?? ''),
                    'email'       => strtolower($r->email ?? ''),
                    'final_score' => (int)$r->final_score,
                    'pontos'      => (int)$r->total_pontos,
                    'multi_um'    => (int)$r->total_multi_um,
                    'multi_dois'  => (int)$r->total_multi_dois,
                    'multi_tres'  => (int)$r->total_multi_tres,
                ];
                $log[] = ['msg' => "1 ".substr($r->categoria,0,35).": {$r->callsign} — ".number_format($r->final_score), 'tipo' => 'ok'];
                $salvar(1, $log);
            }
        }
        if ($catAtual !== null) { $resumoCats[] = $this->buildCatResumo($catAtual, $catBuffer); }

        $fim=microtime(true); $seg=$fim-$ini;
        $tempo=$seg>=60?number_format($seg/60,2).' min':number_format($seg,1).' seg';
        $log[] = ['msg' => "Concluido em {$tempo} | ".count($resumoCats)." categorias.", 'tipo' => 'ok'];

        ContestEtapa::concluir('9',['total_processados'=>$porCategoria->count(),'total_validos'=>count($resumoCats),'tempo_gasto'=>$tempo]);
        activity()->causedBy(auth()->user())->log("Etapa 10: ".count($resumoCats)." categorias (contest #{$cid}).");

        session()->put('resultado_status',    'concluido');
        session()->put('resultado_total',     2);
        session()->put('resultado_atual',     2);
        session()->put('resultado_progresso', array_slice($log, -30));
        session()->put('resultado_concluido', true);
        session()->put('resultado_resultado', [
            'total_ops'=>$porCategoria->count(),'total_cats'=>count($resumoCats),
            'grand_total'=>$grandTotal,'lideres'=>$lideres,'resumo_cats'=>$resumoCats,
            '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]);
    }

    private function buildCatResumo(string $cat, array $buffer): array
    {
        return [
            'nome'      => $cat,
            'total_ops' => count($buffer),
            'top3'      => array_map(fn($r) => [
                'rk'          => $r->rk,
                'callsign'    => $r->callsign,
                'nome'        => $r->nome,
                'final_score' => (int)$r->final_score,
                'qsos'        => (int)$r->total_qsos_validos,
                'pontos'      => (int)$r->total_pontos,
                'reducao'     => $r->percentual_reducao,
            ], array_slice($buffer, 0, 3)),
        ];
    }

    // ════════════════════════════════════════════════════════════════════════
    // ETAPA 11 — Records
    // ════════════════════════════════════════════════════════════════════════

    public function indexRecords()
    {
        $cid = ContestDate::ativo()?->id;
        $totalCampeoes = $cid
            ? DB::table('resultados_final')->where('contest_id',$cid)->where('rk',1)->count()
            : DB::table('resultados_final')->where('rk',1)->count();
        $totalRecords  = DB::table('records')->count();
        return view('processamento.records', compact('totalCampeoes','totalRecords'));
    }

    public function executarRecords(Request $request)
    {
        $request->validate(
            ['confirmacao' => ['required','in:CONFIRMAR']],
            ['confirmacao.in' => 'Digite exatamente CONFIRMAR (maiusculas).']
        );
        session([
            'records_status'    => 'processando',
            'records_progresso' => [],
            'records_total'     => 0,
            'records_atual'     => 0,
            'records_concluido' => false,
            'records_resultado' => null,
        ]);
        return redirect()->route('processamento.records.progresso');
    }

    public function progressoRecords()
    {
        if (session('records_status') === null) {
            return redirect()->route('processamento.records')
                             ->with('erro', 'Inicie pela tela de Records.');
        }
        return view('processamento.records-progresso');
    }

    public function statusRecords()
    {
        return response()->json([
            'status'    => session('records_status',    'aguardando'),
            'total'     => session('records_total',     0),
            'atual'     => session('records_atual',     0),
            'progresso' => session('records_progresso', []),
            'concluido' => session('records_concluido', false),
            'resultado' => session('records_resultado', null),
        ]);
    }

    public function processarRecords(Request $request)
    {
        if (session('records_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 $atual, int $total, array $log) {
            session()->put('records_status',    'processando');
            session()->put('records_atual',     $atual);
            session()->put('records_total',     $total);
            session()->put('records_progresso', array_slice($log, -30));
            session()->save();
        };

        $log[] = ['msg' => "Buscando campeoes (rk=1) do contest #{$cid}...", 'tipo' => 'info'];
        $salvar(0, 1, $log);

        // Busca campeões apenas do contest ativo
        $campeoes = DB::table('resultados_final')
            ->where('contest_id', $cid)
            ->where('rk', 1)
            ->select('categoria','callsign','nome','final_score')
            ->get();

        $total = $campeoes->count();
        if ($total === 0) {
            $log[] = ['msg' => 'Nenhum campeão encontrado. Execute a Etapa 9 primeiro.', 'tipo' => 'erro'];
            $salvar(0, 0, $log);
            return response()->json(['ok' => false]);
        }

        $log[] = ['msg' => "{$total} campeoes encontrados. Verificando recordes...", 'tipo' => 'info'];
        $salvar(0, $total, $log);

        $novosRecords=0; $mantidos=0; $semRecord=0; $detalhes=[];

        foreach ($campeoes as $idx => $c) {
            $atual = $idx + 1;
            $record = DB::table('records')->where('category', $c->categoria)->first();

            if (!$record) {
                $semRecord++;
                $log[] = ['msg' => "-- {$c->categoria}: sem registro em records.", 'tipo' => 'dup'];
                $salvar($atual, $total, $log);
                continue;
            }

            if ($c->final_score > $record->final_score_ant) {
                DB::table('records')->where('category', $c->categoria)->update([
                    'final_score_atu' => $c->final_score,
                    'callsign_atu'    => $c->callsign,
                    'name_atu'        => $c->nome,
                ]);
                $novosRecords++;
                $detalhes[] = ['categoria'=>$c->categoria,'callsign_atu'=>$c->callsign,
                               'score_atu'=>(int)$c->final_score,'callsign_ant'=>$record->callsign_ant,
                               'score_ant'=>(int)$record->final_score_ant,'novo'=>true];
                $log[] = ['msg' => "★ NOVO RECORD: {$c->categoria} | {$c->callsign} ".
                    number_format($c->final_score)." (ant: ".number_format($record->final_score_ant).")", 'tipo' => 'ok'];
            } else {
                DB::table('records')->where('category', $c->categoria)->update([
                    'final_score_atu' => $record->final_score_ant,
                    'callsign_atu'    => $record->callsign_ant,
                    'name_atu'        => $record->name_ant,
                ]);
                $mantidos++;
                $detalhes[] = ['categoria'=>$c->categoria,'callsign_atu'=>$c->callsign,
                               'score_atu'=>(int)$c->final_score,'callsign_ant'=>$record->callsign_ant,
                               'score_ant'=>(int)$record->final_score_ant,'novo'=>false];
                $log[] = ['msg' => "  {$c->categoria} | Record mantido: {$record->callsign_ant} ".number_format($record->final_score_ant), 'tipo' => 'arq'];
            }
            $salvar($atual, $total, $log);
        }

        $fim=microtime(true); $seg=$fim-$ini;
        $tempo=$seg>=60?number_format($seg/60,2).' min':number_format($seg,1).' seg';
        $log[] = ['msg' => "Concluido em {$tempo} | {$novosRecords} novos records | {$mantidos} mantidos.", 'tipo' => 'ok'];

        ContestEtapa::concluir('10',['total_processados'=>$total,'total_validos'=>$novosRecords,'total_invalidos'=>$mantidos,'tempo_gasto'=>$tempo]);
        activity()->causedBy(auth()->user())->log("Etapa 11: {$novosRecords} novos records (contest #{$cid}).");

        session()->put('records_status',    'concluido');
        session()->put('records_total',     $total);
        session()->put('records_atual',     $total);
        session()->put('records_progresso', array_slice($log, -30));
        session()->put('records_concluido', true);
        session()->put('records_resultado', [
            'total_campeoes'=>$total,'novos_records'=>$novosRecords,'mantidos'=>$mantidos,
            'sem_record'=>$semRecord,'detalhes'=>$detalhes,
            '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 11: Encerrar Contest ─────────────────────────────────────────────
    public function encerrar()
    {
        $contestAtivo = ContestDate::ativo();
        $proximo      = $this->calcularProximoContest();
        $status       = session('encerrar_status', 'aguardando');
        $concluido    = session('encerrar_concluido', false);
        $resultado    = session('encerrar_resultado', null);

        session()->put('encerrar_status', 'processando');

        return view('processamento.encerrar', compact('contestAtivo','proximo','status','concluido','resultado'));
    }

    public function progressoEncerrar()
    {
        return response()->json([
            'status'    => session('encerrar_status',   'aguardando'),
            'progresso' => session('encerrar_progresso', []),
            'concluido' => session('encerrar_concluido', false),
            'resultado' => session('encerrar_resultado', null),
            'total'     => session('encerrar_total',     4),
            'atual'     => session('encerrar_atual',     0),
        ]);
    }

    public function processarEncerrar(\Illuminate\Http\Request $request)
    {
        session()->put('encerrar_status', 'processando');
        session()->save();

        $ini          = microtime(true);
        $log          = [];
        $contestAtivo = ContestDate::ativo();

        $salvar = function($atual, $total, $msg) use (&$log) {
            $log[] = ['msg' => $msg, 'tipo' => 'ok'];
            session()->put('encerrar_progresso', array_slice($log, -30));
            session()->put('encerrar_atual',     $atual);
            session()->put('encerrar_total',     $total);
            session()->save();
        };

        try {
            // Passo 1: mover records atual → anterior
            DB::statement("
                UPDATE records SET
                    callsign_ant    = COALESCE(NULLIF(callsign_atu,''),    callsign_ant),
                    name_ant        = COALESCE(NULLIF(name_atu,''),        name_ant),
                    final_score_ant = COALESCE(NULLIF(final_score_atu,0),  final_score_ant),
                    callsign_atu    = '',
                    name_atu        = '',
                    final_score_atu = 0
            ");
            $salvar(1, 4, "Records: atual → anterior. Campos atuais zerados.");

            // Passo 2: marcar contest atual como Encerrado (flag = 2)
            DB::table('contest_date')->where('flag', 1)->update(['flag' => 2]);
            $salvar(2, 4, "Contest marcado como Encerrado (flag=2). Dados preservados no banco.");

            // Passo 3: inserir próximo contest (flag=0) + criar etapas
            $proximo = $this->calcularProximoContest();
            $novoId  = DB::table('contest_date')->insertGetId([
                'name'        => 'LABRE-DX',
                'start_date'  => $proximo['start_date'],
                'end_date'    => $proximo['end_date'],
                'limit_young' => $proximo['limit_young'],
                'inicio_log'  => $proximo['inicio_log'],
                'limit_log'   => $proximo['limit_log'],
                'flag'        => 0,
            ]);
            $etapasNomes = [
                'A'=>'Importar LOGs','1'=>'Juntar LOGs','2'=>'Validar QSOs',
                '3'=>'Validar Tempo/Banda','4'=>'Claimed Score','5'=>'Validar Contatos',
                '6'=>'Sem LOGs / DUPs','7'=>'Pontos+Multi+FS','8'=>'Final Score',
                '9'=>'Resultado Final','10'=>'Records','11'=>'Encerrar Contest',
            ];
            foreach ($etapasNomes as $e => $n) {
                DB::table('contest_etapas')->insert([
                    'etapa'=>$e,'nome'=>$n,'contest_id'=>$novoId,
                    'status'=>'pendente','segundos_gastos'=>0,
                ]);
            }

            // Criar diretório físico do próximo ano para receber os LOGs
            $anoProximo  = \Carbon\Carbon::parse($proximo['start_date'])->year;
            $dirProximo  = config('contest.logs_base_dir') . DIRECTORY_SEPARATOR . $anoProximo;
            if (!is_dir($dirProximo)) {
                mkdir($dirProximo, 0755, true);
                $salvar(3, 4, "Próximo contest #{$novoId} criado (flag=0). Diretório criado: inputs/LOGsRecebidosPorAno/{$anoProximo}/");
            } else {
                $salvar(3, 4, "Próximo contest #{$novoId} criado (flag=0). Diretório já existe: inputs/LOGsRecebidosPorAno/{$anoProximo}/");
            }

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

            ContestEtapa::concluir('11',['total_processados'=>4,'tempo_gasto'=>$tempo]);
            $salvar(4, 4, "Concluído em {$tempo}. Use 'Arquivar' em Gestão de Contests para backup/limpeza.");

        } catch (\Throwable $e) {
            $log[] = ['msg' => "ERRO: " . $e->getMessage(), 'tipo' => 'erro'];
            session()->put('encerrar_status',    'erro');
            session()->put('encerrar_progresso', array_slice($log, -30));
            session()->save();
            return response()->json(['ok' => false, 'erro' => $e->getMessage()]);
        }

        session()->put('encerrar_status',    'concluido');
        session()->put('encerrar_concluido', true);
        session()->put('encerrar_resultado', ['proximo'=>$proximo,'tempo'=>$tempo]);
        session()->save();
        return response()->json(['ok' => true]);
    }

    private function calcularProximoContest(): array
    {
        $ultimo  = ContestDate::orderByDesc('id')->first();
        $anoBase = $ultimo
            ? (int)\Carbon\Carbon::parse($ultimo->start_date)->format('Y') + 1
            : (int)date('Y') + 1;

        $data = \Carbon\Carbon::create($anoBase, 7, 1)->startOfDay();
        while ($data->dayOfWeek !== 6) { $data->addDay(); }
        $data->addDays(14);

        return [
            'start_date'  => $data->copy()->format('Y-m-d\TH:i'),
            'end_date'    => $data->copy()->addDay()->format('Y-m-d\T').'23:59',
            'limit_young' => $data->copy()->subYears(25)->subDay()->toDateString(),
            'inicio_log'  => $data->toDateString(),
            'limit_log'   => $data->copy()->addDays(5)->toDateString(),
        ];
    }
}
