<?php

namespace App\Services;

use App\Models\EmployeeSnapshot;
use App\Models\Submission;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\UploadedFile;

class SubmissionService
{
    /**
     * Processar nova submissão.
     */
    public static function process(array $data, string $type, ?UploadedFile $file = null): Submission
    {
        $ip = request()->ip();
        $nif = $data['nif'];

        // Marcar submissoes anteriores do mesmo NIF como nao-latest (via hash)
        $nifHash = hash('sha256', $nif);
        Submission::where('nif_hash', $nifHash)->where('is_latest', true)->update(['is_latest' => false]);

        // Normalizar telemóvel
        $data['telemovel'] = ComparisonService::normalizePhone($data['telemovel']);
        $data['contacto_emergencia_telefone'] = ComparisonService::normalizePhone($data['contacto_emergencia_telefone']);

        // Upload comprovativo para R2
        $filePath = null;
        $fileOrigName = null;
        $fileMime = null;
        $fileSize = null;

        if ($file) {
            $extension = $file->getClientOriginalExtension();
            $filename = 'comprovativos/' . date('Y/m') . '/' . uniqid('comp_') . '.' . $extension;
            Storage::disk('r2')->put($filename, file_get_contents($file), 'private');
            $filePath = $filename;
            $fileOrigName = $file->getClientOriginalName();
            $fileMime = $file->getMimeType();
            $fileSize = $file->getSize();
        }

        // Tentar match com snapshot
        $snapshot = null;
        $diffData = null;
        $flagSemCorrespondencia = false;
        $flagInconsistencia = false;
        $status = 'novo';
        $suspicionScore = 0;

        if ($type === 'update') {
            $snapshot = EmployeeSnapshot::where('nif_hash', $nifHash)
                ->where('data_nascimento', $data['data_nascimento'])
                ->first();

            if ($snapshot) {
                $comparison = ComparisonService::compareWithSnapshot(
                    new Submission($data + ['morada_original' => $data['morada_original'], 'mudou_morada' => $data['mudou_morada'] ?? false]),
                    $snapshot
                );

                $diffData = $comparison['diff'];
                $flagInconsistencia = $comparison['morada_inconsistency'];

                if (!$comparison['has_changes'] && !($data['mudou_morada'] ?? false)) {
                    $status = 'sem_alteracoes_auto';
                } else {
                    $status = 'pendente';
                }
            } else {
                $flagSemCorrespondencia = true;
                $status = 'pendente';
                $suspicionScore += 20;
            }
        }

        // Verificar IP fora de Portugal
        $flagIpForaPt = self::isIpOutsidePortugal($ip);
        if ($flagIpForaPt) $suspicionScore += 15;

        // Verificar se IP está degradado
        $degraded = \App\Models\BlockedIp::isDegraded($ip);
        if ($degraded) $suspicionScore += 30;

        $submission = Submission::create([
            'type' => $type === 'update' ? 'update' : 'new_admission',
            'nome_completo' => $data['nome_completo'],
            'nif' => $nif,
            'data_nascimento' => $data['data_nascimento'],
            'email' => $data['email'],
            'telemovel' => $data['telemovel'],
            'contacto_emergencia_nome' => $data['contacto_emergencia_nome'],
            'contacto_emergencia_relacao' => $data['contacto_emergencia_relacao'],
            'contacto_emergencia_telefone' => $data['contacto_emergencia_telefone'],
            'morada_original' => $data['morada_original'],
            'mudou_morada' => $data['mudou_morada'] ?? false,
            'estado_civil' => $data['estado_civil'],
            'nr_dependentes' => $data['nr_dependentes'],
            'habilitacoes_literarias' => $data['habilitacoes_literarias'],
            'comprovativo_path' => $filePath,
            'comprovativo_original_name' => $fileOrigName,
            'comprovativo_mime' => $fileMime,
            'comprovativo_size' => $fileSize,
            'status' => $status,
            'flag_sem_correspondencia' => $flagSemCorrespondencia,
            'flag_ip_fora_pt' => $flagIpForaPt,
            'flag_inconsistencia' => $flagInconsistencia,
            'flag_suspeito' => $suspicionScore >= 30,
            'suspicion_score' => $suspicionScore,
            'snapshot_match_id' => $snapshot?->id,
            'diff_data' => $diffData,
            'is_latest' => true,
            'ip_address' => $ip,
            'ip_hash' => hash('sha256', $ip . config('app.key')),
            'user_agent' => request()->userAgent(),
            'declaracao_verdade' => $data['declaracao_verdade'] ?? false,
        ]);

        return $submission;
    }

    /**
     * Verificar se IP está fora de Portugal (heurística simples via timezone/header).
     */
    public static function isIpOutsidePortugal(string $ip): bool
    {
        // Para IPs privados/locais, considerar como PT
        if (in_array($ip, ['127.0.0.1', '::1']) || str_starts_with($ip, '192.168.') || str_starts_with($ip, '10.')) {
            return false;
        }

        // Tentar usar geoip via API gratuita (ip-api.com) com cache
        try {
            $cacheKey = 'geoip_' . md5($ip);
            $country = cache()->remember($cacheKey, 86400, function () use ($ip) {
                $ctx = stream_context_create(['http' => ['timeout' => 3]]);
                $response = @file_get_contents("http://ip-api.com/json/{$ip}?fields=countryCode", false, $ctx);
                if ($response) {
                    $data = json_decode($response, true);
                    return $data['countryCode'] ?? 'XX';
                }
                return 'XX'; // Se falhar, marcar como desconhecido (não flag)
            });

            return !in_array($country, ['PT', 'XX']);
        } catch (\Exception $e) {
            return false; // Em caso de erro, não penalizar
        }
    }

    /**
     * Gerar URL assinada temporária para comprovativo.
     */
    public static function getSignedUrl(Submission $submission): ?string
    {
        if (!$submission->comprovativo_path) return null;

        return Storage::disk('r2')->temporaryUrl(
            $submission->comprovativo_path,
            now()->addMinutes(15)
        );
    }
}
