<?php
declare(strict_types=1);

require_once __DIR__ . '/../config/helpers.php';
require_once __DIR__ . '/../config/mercado_pago_helpers.php';
require_once __DIR__ . '/../config/corrida_ofertas_helpers.php';

$data = input_json() + $_GET;
require_fields($data, ['id_corrida', 'id_passageiro']);

$idCorrida = (int) $data['id_corrida'];
$idPassageiro = (int) $data['id_passageiro'];

if ($idCorrida <= 0 || $idPassageiro <= 0) {
    json_fail('Dados invalidos para gerar Pix da corrida.');
}

function pix_corrida_row_payload(array $row): array
{
    $raw = json_decode((string) ($row['raw_response'] ?? ''), true);
    if (!is_array($raw)) {
        $raw = [];
    }

    return mp_pix_payload_publico($raw, $row);
}

function pix_corrida_webhook_privado(string $webhookUrl): bool
{
    $host = parse_url($webhookUrl, PHP_URL_HOST);
    return !$host
        || in_array($host, ['localhost', '127.0.0.1'], true)
        || str_starts_with((string) $host, '192.168.')
        || str_starts_with((string) $host, '10.')
        || preg_match('/^172\.(1[6-9]|2\d|3[0-1])\./', (string) $host);
}

try {
    $pdo = db();
    if (!mp_table_exists($pdo, 'pagamentos_corridas')) {
        json_fail('Tabela pagamentos_corridas nao existe. Rode a atualizacao do banco.', 500);
    }

    $selectMpExternal = mp_column_exists($pdo, 'corridas', 'mp_external_reference')
        ? 'c.mp_external_reference'
        : 'NULL AS mp_external_reference';
    $stmt = $pdo->prepare(
        'SELECT c.id, c.id_passageiro, c.id_motorista, c.status, c.valor,
                COALESCE(c.saldo_negativo_cobrado, 0) AS saldo_negativo_cobrado,
                COALESCE(c.forma_pagamento, "dinheiro") AS forma_pagamento,
                COALESCE(c.forma_pagamento_detalhe, "dinheiro_pix") AS forma_pagamento_detalhe,
                ' . $selectMpExternal . ',
                p.nome AS passageiro_nome, p.email AS passageiro_email
         FROM corridas c
         LEFT JOIN usuarios p ON p.id = c.id_passageiro
         WHERE c.id = ?
         LIMIT 1'
    );
    $stmt->execute([$idCorrida]);
    $corrida = $stmt->fetch();
    if (!$corrida) {
        json_fail('Corrida nao encontrada.', 404);
    }
    if ((int) ($corrida['id_passageiro'] ?? 0) !== $idPassageiro) {
        json_fail('Essa corrida nao pertence a este passageiro.', 403);
    }
    if (($corrida['status'] ?? '') !== 'pendente') {
        json_fail('Pix disponivel somente antes da corrida ser aceita.', 409);
    }

    $forma = strtolower(trim((string) ($corrida['forma_pagamento'] ?? '')));
    $detalhe = strtolower(trim((string) ($corrida['forma_pagamento_detalhe'] ?? '')));
    if ($forma !== 'online' || $detalhe !== 'pix_online') {
        json_fail('Essa corrida nao foi solicitada com Pix Online.', 409);
    }

    $externalReference = trim((string) ($corrida['mp_external_reference'] ?? ''));
    if ($externalReference === '') {
        $externalReference = mp_external_reference('corrida', $idCorrida);
    }

    $existing = $pdo->prepare(
        'SELECT *
         FROM pagamentos_corridas
         WHERE external_reference = ?
            OR (id_corrida = ? AND metodo = "pix_online" AND status IN ("criado", "pendente", "autorizado", "aprovado"))
         ORDER BY id DESC
         LIMIT 1'
    );
    $existing->execute([$externalReference, $idCorrida]);
    $row = $existing->fetch();
    if ($row) {
        $payload = pix_corrida_row_payload($row);
        if (in_array((string) $row['status'], ['pendente', 'autorizado', 'aprovado'], true) && ($payload['qr_code_base64'] !== '' || $payload['status'] === 'aprovado')) {
            json_ok(['pagamento' => $payload]);
        }
    }

    $valor = mp_money((float) ($corrida['valor'] ?? 0));
    if ($valor <= 0) {
        json_fail('Valor da corrida invalido para Pix.');
    }

    $payerEmail = trim((string) ($corrida['passageiro_email'] ?? ''));
    if ($payerEmail === '') {
        $payerEmail = 'passageiro' . $idPassageiro . '@bulo.local';
    }

    $request = [
        'transaction_amount' => $valor,
        'description' => 'Bulo - corrida #' . $idCorrida,
        'payment_method_id' => 'pix',
        'external_reference' => $externalReference,
        'payer' => [
            'email' => $payerEmail,
            'first_name' => trim((string) ($corrida['passageiro_nome'] ?? 'Passageiro')) ?: 'Passageiro',
        ],
    ];

    $webhookUrl = trim(mp_config_valor($pdo, 'mp_webhook_url'));
    if ($webhookUrl !== '' && !pix_corrida_webhook_privado($webhookUrl)) {
        $request['notification_url'] = $webhookUrl;
    }

    $response = mp_http_json_request(
        'POST',
        'https://api.mercadopago.com/v1/payments',
        ['Authorization: Bearer ' . mp_access_token_plataforma($pdo)],
        $request,
        'bulo-corrida-pix-' . $idCorrida
    );

    $status = mp_status_pagamento_local((string) ($response['status'] ?? 'pending'));
    $mpPaymentId = (string) ($response['id'] ?? '');
    $valores = mp_corrida_valores(
        $valor,
        (float) ($corrida['saldo_negativo_cobrado'] ?? 0),
        mp_taxa_gateway_de_pagamento($response)
    );
    $config = mp_config($pdo);

    $ins = $pdo->prepare(
        'INSERT INTO pagamentos_corridas
          (id_corrida, id_passageiro, id_motorista, ambiente, external_reference, mp_payment_id, metodo, status,
           valor_total, valor_motorista, valor_plataforma, taxa_gateway, application_fee, raw_request, raw_response)
         VALUES (?, ?, NULL, ?, ?, ?, "pix_online", ?, ?, ?, ?, ?, ?, ?, ?)
         ON DUPLICATE KEY UPDATE
           mp_payment_id = VALUES(mp_payment_id),
           metodo = VALUES(metodo),
           status = VALUES(status),
           valor_total = VALUES(valor_total),
           valor_motorista = VALUES(valor_motorista),
           valor_plataforma = VALUES(valor_plataforma),
           taxa_gateway = VALUES(taxa_gateway),
           application_fee = VALUES(application_fee),
           raw_request = VALUES(raw_request),
           raw_response = VALUES(raw_response),
           atualizado_em = CURRENT_TIMESTAMP'
    );
    $ins->execute([
        $idCorrida,
        $idPassageiro,
        $config['ambiente'],
        $externalReference,
        $mpPaymentId !== '' ? $mpPaymentId : null,
        $status,
        $valores['valor_total'],
        $valores['valor_motorista'],
        $valores['valor_plataforma'],
        $valores['taxa_gateway'],
        $valores['application_fee'],
        json_encode($request, JSON_UNESCAPED_UNICODE),
        json_encode($response, JSON_UNESCAPED_UNICODE),
    ]);

    $idPagamento = (int) $pdo->lastInsertId();
    if ($idPagamento <= 0) {
        $lookup = $pdo->prepare('SELECT id FROM pagamentos_corridas WHERE external_reference = ? LIMIT 1');
        $lookup->execute([$externalReference]);
        $idPagamento = (int) $lookup->fetchColumn();
    }

    $sets = [];
    $params = [];
    if (mp_column_exists($pdo, 'corridas', 'id_pagamento_gateway')) {
        $sets[] = 'id_pagamento_gateway = ?';
        $params[] = $idPagamento ?: null;
    }
    if (mp_column_exists($pdo, 'corridas', 'status_pagamento')) {
        $sets[] = 'status_pagamento = ?';
        $params[] = $status;
    }
    if (mp_column_exists($pdo, 'corridas', 'mp_payment_id')) {
        $sets[] = 'mp_payment_id = ?';
        $params[] = $mpPaymentId !== '' ? $mpPaymentId : null;
    }
    if (mp_column_exists($pdo, 'corridas', 'mp_external_reference')) {
        $sets[] = 'mp_external_reference = ?';
        $params[] = $externalReference;
    }
    if ($sets) {
        $params[] = $idCorrida;
        $up = $pdo->prepare('UPDATE corridas SET ' . implode(', ', $sets) . ' WHERE id = ?');
        $up->execute($params);
    }

    json_ok([
        'pagamento' => mp_pix_payload_publico($response, [
            'id' => $idPagamento,
            'external_reference' => $externalReference,
            'mp_payment_id' => $mpPaymentId,
            'valor_total' => $valores['valor_total'],
            'valor_motorista' => $valores['valor_motorista'],
            'valor_plataforma' => $valores['valor_plataforma'],
            'taxa_gateway' => $valores['taxa_gateway'],
            'status' => $status,
        ]),
    ]);
} catch (Throwable $e) {
    json_fail(
        mp_gateway_exception_message($e, 'Erro ao gerar Pix da corrida.'),
        $e instanceof MercadoPagoApiException ? 422 : 500,
        mp_gateway_exception_payload($e)
    );
}
