<?php
declare(strict_types=1);

require_once __DIR__ . '/_bootstrap.php';
require_once __DIR__ . '/../config/veiculo_modelo_base.php';
admin_require_login();

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: configuracoes_veiculos.php');
    exit;
}

$acao = trim((string) ($_POST['acao'] ?? ''));

try {
    $pdo = db();

    if ($acao === 'importar_fipe') {
        $token = trim((string) ($_POST['fipe_token'] ?? ''));
        $anoMinimo = (int) ($_POST['ano_minimo'] ?? ((int) date('Y') - 12));
        $offsetMarcas = max(0, (int) ($_POST['offset_marcas'] ?? 0));
        $limiteMarcas = max(1, min(30, (int) ($_POST['limite_marcas'] ?? 5)));

        $resultado = admin_importar_fipe_catalogo($pdo, $token, $anoMinimo, $offsetMarcas, $limiteMarcas);
        $proximoOffset = $offsetMarcas + $resultado['marcas_processadas'];
        $fim = $proximoOffset >= $resultado['total_marcas'];

        admin_flash(
            'FIPE importada: ' .
            $resultado['marcas_processadas'] . ' marcas processadas, ' .
            $resultado['modelos_importados'] . ' modelos adicionados/confirmados, ' .
            $resultado['requisicoes'] . ' requisicoes. ' .
            ($fim ? 'Todos os lotes foram processados.' : 'Próximo lote: pular ' . $proximoOffset . ' marcas.')
        );
    } elseif ($acao === 'adicionar_modelo') {
        $idMarca = (int) ($_POST['id_marca'] ?? 0);
        $novaMarca = trim((string) ($_POST['nova_marca'] ?? ''));
        $modelo = trim((string) ($_POST['modelo'] ?? ''));

        if ($modelo === '') {
            throw new RuntimeException('Informe o modelo do veículo.');
        }

        $pdo->beginTransaction();

        if ($idMarca <= 0) {
            if ($novaMarca === '') {
                throw new RuntimeException('Escolha uma marca existente ou informe uma nova marca.');
            }
            $marcaStmt = $pdo->prepare(
                'INSERT INTO veiculo_marcas_catalogo (nome, ativo)
                 VALUES (?, 1)
                 ON DUPLICATE KEY UPDATE ativo = 1, id = LAST_INSERT_ID(id)'
            );
            $marcaStmt->execute([$novaMarca]);
            $idMarca = (int) $pdo->lastInsertId();
        } else {
            $check = $pdo->prepare('SELECT id FROM veiculo_marcas_catalogo WHERE id = ? LIMIT 1');
            $check->execute([$idMarca]);
            if (!$check->fetchColumn()) {
                throw new RuntimeException('Marca invalida.');
            }
        }

        $stmt = $pdo->prepare(
            'INSERT INTO veiculo_modelos_catalogo
             (id_marca, nome, categoria_economica, categoria_plus, categoria_pro, ativo)
             VALUES (?, ?, ?, ?, ?, 1)
             ON DUPLICATE KEY UPDATE
                categoria_economica = VALUES(categoria_economica),
                categoria_plus = VALUES(categoria_plus),
                categoria_pro = VALUES(categoria_pro),
                ativo = 1'
        );
        $stmt->execute([
            $idMarca,
            $modelo,
            isset($_POST['categoria_economica']) ? 1 : 0,
            isset($_POST['categoria_plus']) ? 1 : 0,
            isset($_POST['categoria_pro']) ? 1 : 0,
        ]);

        $pdo->commit();
        admin_flash('Veículo adicionado ao catálogo.');
    } elseif ($acao === 'adicionar_cor') {
        $cor = trim((string) ($_POST['cor_nome'] ?? ''));
        if ($cor === '') {
            throw new RuntimeException('Informe a cor.');
        }

        $stmt = $pdo->prepare(
            'INSERT INTO veiculo_cores_catalogo (nome, ativo)
             VALUES (?, 1)
             ON DUPLICATE KEY UPDATE ativo = 1'
        );
        $stmt->execute([$cor]);
        admin_flash('Cor adicionada ao catalogo.');
    } elseif ($acao === 'salvar_categorias') {
        $modelosPost = $_POST['modelos'] ?? [];
        if (!is_array($modelosPost)) {
            $modelosPost = [];
        }

        $ids = array_map('intval', array_keys($modelosPost));
        if (!$ids) {
            admin_flash('Nenhum modelo para atualizar.', 'error');
            header('Location: configuracoes_veiculos.php');
            exit;
        }

        $stmt = $pdo->prepare(
            'UPDATE veiculo_modelos_catalogo
             SET categoria_economica = ?,
                 categoria_plus = ?,
                 categoria_pro = ?,
                 ativo = ?
             WHERE id = ?'
        );

        foreach ($modelosPost as $id => $dados) {
            if (!is_array($dados)) {
                $dados = [];
            }
            $stmt->execute([
                isset($dados['economica']) ? 1 : 0,
                isset($dados['plus']) ? 1 : 0,
                isset($dados['pro']) ? 1 : 0,
                isset($dados['ativo']) ? 1 : 0,
                (int) $id,
            ]);
        }

        admin_flash('Categorias salvas.');
    } else {
        throw new RuntimeException('Acao invalida.');
    }
} catch (Throwable $e) {
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    admin_flash('Erro ao salvar catalogo: ' . $e->getMessage(), 'error');
}

header('Location: configuracoes_veiculos.php');
exit;

function admin_importar_fipe_catalogo(PDO $pdo, string $token, int $anoMinimo, int $offset, int $limit): array
{
    $baseUrl = 'https://fipe.parallelum.com.br/api/v2';
    $requisicoes = 0;
    $brandsPayload = admin_fipe_get($baseUrl . '/cars/brands', $token);
    $requisicoes++;
    $brands = admin_fipe_lista($brandsPayload);
    $totalMarcas = count($brands);
    $lote = array_slice($brands, $offset, $limit);
    $modelosImportados = 0;
    $marcasProcessadas = 0;

    foreach ($lote as $brand) {
        if (!is_array($brand)) {
            continue;
        }

        $brandCode = admin_fipe_item_code($brand);
        $brandName = admin_fipe_item_name($brand);
        if ($brandCode === '' || $brandName === '') {
            continue;
        }

        $idMarca = admin_catalogo_upsert_marca($pdo, admin_fipe_limpar_marca($brandName));
        $modelos = admin_fipe_modelos_da_marca($baseUrl, $brandCode, $token, $anoMinimo, $requisicoes);

        foreach ($modelos as $modeloNome) {
            $modeloNome = admin_fipe_limpar_nome((string) $modeloNome);
            if ($modeloNome === '') {
                continue;
            }
            admin_catalogo_upsert_modelo($pdo, $idMarca, $modeloNome);
            $modelosImportados++;
        }

        $marcasProcessadas++;
    }

    return [
        'total_marcas' => $totalMarcas,
        'marcas_processadas' => $marcasProcessadas,
        'modelos_importados' => $modelosImportados,
        'requisicoes' => $requisicoes,
    ];
}

function admin_fipe_modelos_da_marca(string $baseUrl, string $brandCode, string $token, int $anoMinimo, int &$requisicoes): array
{
    $modelos = [];
    $years = [];

    try {
        $yearsPayload = admin_fipe_get($baseUrl . '/cars/brands/' . rawurlencode($brandCode) . '/years', $token);
        $requisicoes++;
        $years = admin_fipe_lista($yearsPayload);
    } catch (Throwable) {
        $years = [];
    }

    foreach ($years as $year) {
        if (!is_array($year)) {
            continue;
        }

        $ano = admin_fipe_year_from_item($year);
        if ($ano !== null && $ano < $anoMinimo) {
            continue;
        }

        $yearCode = admin_fipe_item_code($year);
        if ($yearCode === '') {
            continue;
        }

        try {
            $payload = admin_fipe_get(
                $baseUrl . '/cars/brands/' . rawurlencode($brandCode) . '/years/' . rawurlencode($yearCode) . '/models',
                $token
            );
            $requisicoes++;
            foreach (admin_fipe_lista($payload) as $modelo) {
                if (is_array($modelo)) {
                    $nome = admin_fipe_item_name($modelo);
                    if ($nome !== '') {
                        $modelos[$nome] = true;
                    }
                }
            }
        } catch (Throwable) {
            continue;
        }
    }

    if (!$modelos) {
        $payload = admin_fipe_get($baseUrl . '/cars/brands/' . rawurlencode($brandCode) . '/models', $token);
        $requisicoes++;
        foreach (admin_fipe_lista($payload) as $modelo) {
            if (is_array($modelo)) {
                $nome = admin_fipe_item_name($modelo);
                if ($nome !== '') {
                    $modelos[$nome] = true;
                }
            }
        }
    }

    return array_keys($modelos);
}

function admin_fipe_get(string $url, string $token): array
{
    $headers = [
        'Accept: application/json',
        'User-Agent: BuloAdmin/1.0',
    ];
    if ($token !== '') {
        $headers[] = 'X-Subscription-Token: ' . $token;
    }

    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTPHEADER => $headers,
        ]);
        $body = curl_exec($ch);
        $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($body === false) {
            throw new RuntimeException('Falha ao consultar FIPE: ' . $error);
        }
    } else {
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'header' => implode("\r\n", $headers),
                'timeout' => 30,
                'ignore_errors' => true,
            ],
        ]);
        $body = @file_get_contents($url, false, $context);
        $status = 0;
        foreach ($http_response_header ?? [] as $header) {
            if (preg_match('/^HTTP\/\S+\s+(\d+)/', $header, $matches)) {
                $status = (int) $matches[1];
                break;
            }
        }

        if ($body === false) {
            throw new RuntimeException('Falha ao consultar FIPE.');
        }
    }

    if ($status >= 400) {
        throw new RuntimeException('FIPE respondeu HTTP ' . $status . '. Verifique o token ou tente um lote menor.');
    }

    $decoded = json_decode((string) $body, true);
    if (!is_array($decoded)) {
        throw new RuntimeException('Resposta invalida da FIPE.');
    }

    return $decoded;
}

function admin_fipe_lista(array $payload): array
{
    if ($payload === [] || array_key_exists(0, $payload)) {
        return $payload;
    }

    foreach (['brands', 'marcas', 'models', 'modelos', 'years', 'anos', 'data'] as $key) {
        if (isset($payload[$key]) && is_array($payload[$key])) {
            return admin_fipe_lista($payload[$key]);
        }
    }

    return [];
}

function admin_fipe_item_code(array $item): string
{
    return trim((string) ($item['code'] ?? $item['codigo'] ?? $item['id'] ?? ''));
}

function admin_fipe_item_name(array $item): string
{
    return trim((string) ($item['name'] ?? $item['nome'] ?? $item['model'] ?? $item['modelo'] ?? ''));
}

function admin_fipe_year_from_item(array $item): ?int
{
    $texto = admin_fipe_item_name($item) . ' ' . admin_fipe_item_code($item);
    if (preg_match('/(?:^|\D)((?:19|20)\d{2})(?:\D|$)/', $texto, $matches)) {
        return (int) $matches[1];
    }

    if (stripos($texto, 'zero') !== false || str_starts_with(admin_fipe_item_code($item), '32000')) {
        return (int) date('Y');
    }

    return null;
}

function admin_fipe_limpar_nome(string $nome): string
{
    $nome = preg_replace('/\s+/', ' ', trim($nome));
    return veiculo_modelo_base($nome ?? '');
}

function admin_fipe_limpar_marca(string $nome): string
{
    $nome = trim($nome);
    $aliases = [
        'GM - Chevrolet' => 'Chevrolet',
        'VW - VolksWagen' => 'Volkswagen',
        'Kia Motors' => 'Kia',
        'Citroën' => 'Citroen',
        'CitroÃ«n' => 'Citroen',
        'Caoa Chery/Chery' => 'Caoa Chery',
        'GREAT WALL' => 'GWM',
    ];

    return $aliases[$nome] ?? $nome;
}

function admin_catalogo_upsert_marca(PDO $pdo, string $nome): int
{
    $stmt = $pdo->prepare(
        'INSERT INTO veiculo_marcas_catalogo (nome, ativo)
         VALUES (?, 1)
         ON DUPLICATE KEY UPDATE ativo = 1, id = LAST_INSERT_ID(id)'
    );
    $stmt->execute([$nome]);

    return (int) $pdo->lastInsertId();
}

function admin_catalogo_upsert_modelo(PDO $pdo, int $idMarca, string $nome): int
{
    $stmt = $pdo->prepare(
        'INSERT INTO veiculo_modelos_catalogo
         (id_marca, nome, categoria_economica, categoria_plus, categoria_pro, ativo)
         VALUES (?, ?, 1, 0, 0, 1)
         ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)'
    );
    $stmt->execute([$idMarca, $nome]);

    return (int) $pdo->lastInsertId();
}
