<?php
namespace App\Http\Controllers\Public;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
 
class LogSubmissionController extends Controller
{
    // ── Resolve o diretório do ano do contest ativo ──────────────────────────────
    private function uploadDir(): string
    {
        try {
            $contest = DB::table('contest_date')->where('flag', 1)->first()
                    ?? DB::table('contest_date')->orderByDesc('id')->first();
            $ano = $contest?->start_date
                ? \Carbon\Carbon::parse($contest->start_date)->year
                : (int) date('Y');
        } catch (\Throwable) {
            $ano = (int) date('Y');
        }
        $dir = config('contest.logs_base_dir') . DIRECTORY_SEPARATOR . $ano;
        @mkdir($dir, 0755, true);
        return $dir;
    }
 
    private function backupDir(): string
    {
        try {
            $contest = DB::table('contest_date')->where('flag', 1)->first()
                    ?? DB::table('contest_date')->orderByDesc('id')->first();
            $ano = $contest?->start_date
                ? \Carbon\Carbon::parse($contest->start_date)->year
                : (int) date('Y');
        } catch (\Throwable) {
            $ano = (int) date('Y');
        }
        $dir = base_path('inputs' . DIRECTORY_SEPARATOR . 'LOGsAnterioresPorAno' . DIRECTORY_SEPARATOR . $ano);
        @mkdir($dir, 0755, true);
        return $dir;
    }
 
    // ── Formulário público de envio ───────────────────────────────────────────
    public function index()
    {
        // Tenta flag=1 primeiro; se não encontrar, pega o mais recente
        $contest = DB::table('contest_date')->where('flag', 1)->first()
                ?? DB::table('contest_date')->orderByDesc('id')->first();
 
        $exchanges    = DB::table('exchange')->orderBy('exchange_value')->pluck('exchange_value');
        $clubesBrasil = DB::table('clubsbrasil')->orderBy('nome')->pluck('nome');
        $labresHQ     = DB::table('estaduais')->orderBy('estadual')->pluck('estadual');
 
        if (!$contest) {
            return view('public.log-submission', [
                'contest'       => null,
                'contestAberto' => false,
                'exchanges'     => $exchanges,
                'clubesBrasil'  => $clubesBrasil,
                'labresHQ'      => $labresHQ,
            ]);
        }
 
        $hoje          = now()->startOfDay();
        $inicio        = \Carbon\Carbon::parse($contest->inicio_log)->startOfDay();
        $limite        = \Carbon\Carbon::parse($contest->limit_log)->endOfDay();
        $contestAberto = $hoje->between($inicio, $limite);
 
        return view('public.log-submission', compact(
            'contest','contestAberto','inicio','limite','exchanges','clubesBrasil','labresHQ'
        ));
    }
 
    // ── GET: data limite para YOUTH (API para JS) ─────────────────────────────
    public function limitYoung()
    {
        $contest = DB::table('contest_date')->where('flag', 1)->first()
                ?? DB::table('contest_date')->orderByDesc('id')->first();
        if (!$contest) {
            return response()->json(['error' => 'Contest não encontrado'], 404);
        }
        return response()->json(['limit_young' => $contest->limit_young]);
    }
 
    // ── POST: processar upload ────────────────────────────────────────────────
    public function store(Request $request)
    {
        // Validação básica dos campos do formulário
        $request->validate([
            'categoria'      => 'required|string',
            'potencia'       => 'required|string',
            'banda'          => 'required|string',
            'modo'           => 'required|string',
            'exchange'       => 'required|string',
            'indicativo'     => 'required|string|max:20',
            'email'          => 'required|email|max:100',
            'club_final'     => 'required|string',
            'arquivo'        => 'required|file|mimes:log,txt|max:2048',
        ], [
            'arquivo.required' => 'O arquivo .log é obrigatório.',
            'arquivo.mimes'    => 'O arquivo deve ter extensão .log',
            'arquivo.max'      => 'O arquivo não pode exceder 2MB.',
        ]);
 
        $indicativo  = strtoupper(trim($request->indicativo));
        $email       = strtolower(trim($request->email));
        $clubEscolhido = $request->club_final;
        $dataNasc    = $request->dataNascimento ?? null;
 
        $newFileName    = "{$indicativo}.log";
        $destPath       = $this->uploadDir() . DIRECTORY_SEPARATOR . $newFileName;
        $backupPath     = $this->backupDir() . DIRECTORY_SEPARATOR . date('YmdHis') . "_{$newFileName}";
        $existe         = file_exists($destPath);
 
        // Confirmação de substituição
        if ($existe && !$request->boolean('confirma_substituir')) {
            // Guarda o arquivo temporariamente na sessão para confirmar
            $tempName = 'temp_' . $indicativo . '_' . time() . '.log';
            $request->file('arquivo')->storeAs('temp_logs', $tempName, 'local');
            session([
                'log_temp'    => $tempName,
                'log_dados'   => $request->except('arquivo'),
                'log_indicativo' => $indicativo,
            ]);
            return back()
                ->with('confirma_substituir', true)
                ->with('indicativo_existente', $indicativo)
                ->withInput();
        }
 
        // Se confirmou substituição, recuperar arquivo temporário da sessão
        if ($existe && $request->boolean('confirma_substituir')) {
            $tempName = session('log_temp');
            if ($tempName && \Illuminate\Support\Facades\Storage::disk('local')->exists("temp_logs/{$tempName}")) {
                // Backup do anterior
                copy($destPath, $backupPath);
                // Mover temporário para destino
                $tempPath = storage_path("app/temp_logs/{$tempName}");
                rename($tempPath, $destPath);
                \Illuminate\Support\Facades\Storage::disk('local')->deleteDirectory('temp_logs');
                session()->forget(['log_temp','log_dados','log_indicativo']);
            } else {
                return back()->with('erro', 'Sessão expirada. Por favor, envie o arquivo novamente.');
            }
        } else {
            // Novo arquivo — mover diretamente
            $request->file('arquivo')->move($this->uploadDir(), $newFileName);
        }
 
        // Ler conteúdo do LOG
        $logContent = file_get_contents($destPath);
        $enc        = mb_detect_encoding($logContent, ['UTF-8','ISO-8859-1','WINDOWS-1252'], true);
        $logContent = mb_convert_encoding($logContent, 'UTF-8', $enc ?: 'UTF-8');
 
        // Equalizar CLUB no arquivo
        $this->equalizarClub($destPath, $clubEscolhido);
 
        // Validar conteúdo
        $validationData = [
            'indicativo'     => $indicativo,
            'email'          => $email,
            'categoria'      => $request->categoria,
            'potencia'       => $request->potencia,
            'banda'          => $request->banda,
            'modo'           => $request->modo,
            'exchange'       => $request->exchange,
            'club'           => $clubEscolhido,
            'dataNascimento' => $dataNasc,
        ];
 
        $errors   = $this->validateLogContent($logContent, $validationData);
        $sucesso  = $existe ? 'substituido' : 'enviado';
 
        // Gravar .txt de recibo
        $recibo = storage_path("app/temp_logs/{$indicativo}.txt");
        @mkdir(dirname($recibo), 0755, true);
        file_put_contents($recibo,
            "Data/Hora: " . now()->format('Y-m-d H:i:s') . "\n" .
            "Indicativo: {$indicativo}\nEmail: {$email}\n" .
            "Categoria: {$request->categoria}\nPotencia: {$request->potencia}\n" .
            "Banda: {$request->banda}\nModo: {$request->modo}\n" .
            "Exchange: {$request->exchange}\nClub: {$clubEscolhido}\n" .
            "Erros:\n" . implode("\n", $errors) . "\n"
        );
 
        // Enviar e-mail de confirmação
        try {
            Mail::send('emails.log-recebido', [
                'indicativo' => $indicativo,
                'sucesso'    => $sucesso,
                'errors'     => $errors,
                'dados'      => $validationData,
            ], function($m) use ($email, $indicativo, $recibo) {
                $m->to($email)
                  ->subject("Confirmação de Recebimento de LOG — {$indicativo} | LABRE-DX Contest")
                  ->from(config('mail.from.address', 'contest@labre.org.br'), 'CONTEST LABRE-DX');
                if (file_exists($recibo)) {
                    $m->attach($recibo, ['as' => "{$indicativo}_recibo.txt"]);
                }
            });
        } catch (\Throwable $e) {
            // E-mail falhou — não bloqueia o upload
        }
 
        return redirect()->route('public.log.index')
            ->with('resultado', [
                'sucesso'  => $sucesso,
                'indicativo'=> $indicativo,
                'errors'   => $errors,
                'email'    => $email,
            ]);
    }
 
    // ── Lista pública de LOGs recebidos ───────────────────────────────────────
    public function lista()
    {
        $arquivos = glob($this->uploadDir() . DIRECTORY_SEPARATOR . '*.log') ?: [];
        $logs = [];
        foreach ($arquivos as $f) {
            $logs[] = pathinfo($f, PATHINFO_FILENAME);
        }
        sort($logs);
        $total = count($logs);
        return view('public.log-lista', compact('logs','total'));
    }
 
    // ── Helpers privados ──────────────────────────────────────────────────────
    private function equalizarClub(string $path, string $clube): void
    {
        $linhas = file($path, FILE_IGNORE_NEW_LINES);
        foreach ($linhas as $i => $linha) {
            if (stripos($linha, 'CLUB:') === 0) {
                $linhas[$i] = 'CLUB: ' . $clube;
                file_put_contents($path, implode("\n", $linhas));
                return;
            }
        }
        // Se não havia CLUB, inserir após a 1ª linha
        array_splice($linhas, 1, 0, 'CLUB: ' . $clube);
        file_put_contents($path, implode("\n", $linhas));
    }
 
    private function validateLogContent(string $content, array $data): array
    {
        $errors = [];
 
        // CALLSIGN
        if (stripos($content, "CALLSIGN: {$data['indicativo']}") === false) {
            $errors[] = "CALLSIGN no LOG não corresponde ao indicativo informado ({$data['indicativo']}).";
        }
        // CONTEST
        if (stripos($content, 'CONTEST: LABRE-DX') === false) {
            $errors[] = "Campo CONTEST não contém 'LABRE-DX'.";
        }
        // CATEGORY-POWER
        if (stripos($content, "CATEGORY-POWER: {$data['potencia']}") === false) {
            $errors[] = "CATEGORY-POWER não corresponde a {$data['potencia']}.";
        }
        // CATEGORY-BAND
        if (stripos($content, "CATEGORY-BAND: {$data['banda']}") === false) {
            $errors[] = "CATEGORY-BAND não corresponde a {$data['banda']}.";
        }
        // CATEGORY-MODE
        if (stripos($content, "CATEGORY-MODE: {$data['modo']}") === false) {
            $errors[] = "CATEGORY-MODE não corresponde a {$data['modo']}.";
        }
        // EMAIL
        if (!preg_match('/EMAIL:\s*([^\s@]+@[^\s@]+\.[^\s@]+)/i', $content, $m) ||
            strtolower(trim($m[1])) !== $data['email']) {
            $errors[] = "EMAIL no LOG não corresponde ao e-mail informado ({$data['email']}).";
        }
        // CATEGORY-TRANSMITTER
        if (!preg_match('/CATEGORY-TRANSMITTER:\s*(ONE|TWO)/i', $content)) {
            $errors[] = "CATEGORY-TRANSMITTER deve ser ONE ou TWO.";
        }
        // Validação da data de nascimento para YOUTH
        if ($data['categoria'] === 'SINGLE-OP-YOUTH' && !empty($data['dataNascimento'])) {
            $contest = DB::table('contest_date')->where('flag', 1)->first();
            if ($contest && strtotime($data['dataNascimento']) < strtotime($contest->limit_young)) {
                $errors[] = "Data de nascimento inválida para categoria YOUTH (deve ser após " .
                    \Carbon\Carbon::parse($contest->limit_young)->format('d/m/Y') . ").";
            }
        }
        // Primeiro QSO — validações básicas
        $lines    = explode("\n", $content);
        $qsoLines = array_filter($lines, fn($l) => str_starts_with(trim($l), 'QSO:'));
        if (empty($qsoLines)) {
            $errors[] = "Nenhuma linha QSO encontrada no LOG.";
        } else {
            $first  = trim(reset($qsoLines));
            $parts  = preg_split('/\s+/', $first);
            if (count($parts) >= 8) {
                $exchSent = $parts[7];
                $callSent = $parts[5];
                if (strcasecmp($callSent, $data['indicativo']) !== 0) {
                    $errors[] = "Call enviado no QSO ({$callSent}) difere do indicativo ({$data['indicativo']}).";
                }
                $exchValido = DB::table('exchange')
                    ->where('exchange_value', $exchSent)->exists();
                if (!$exchValido) {
                    $errors[] = "Exchange enviado no QSO ({$exchSent}) não existe na tabela de exchanges.";
                } elseif (strcasecmp($exchSent, $data['exchange']) !== 0) {
                    $errors[] = "Exchange no QSO ({$exchSent}) difere do informado ({$data['exchange']}).";
                }
            }
        }
        return $errors;
    }
}