<?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() + $_POST + $_GET;
require_fields($data, ['id_corrida', 'id_passageiro', 'card_token']);

$idCorrida = (int) $data['id_corrida'];
$idPassageiro = (int) $data['id_passageiro'];
$cardToken = trim((string) $data['card_token']);
$paymentMethodId = strtolower(trim((string) $data['payment_method_id']));
$idCartao = (int) ($data['id_cartao'] ?? 0);
$issuerId = trim((string) ($data['issuer_id'] ?? ''));
$installments = max(1, (int) ($data['installments'] ?? 1));
$docType = strtoupper(trim((string) ($data['doc_type'] ?? 'CPF'))) ?: 'CPF';
$docNumber = preg_replace('/\D+/', '', (string) ($data['doc_number'] ?? ''));

if ($idCorrida <= 0 || $idPassageiro <= 0 || $cardToken === '' || $paymentMethodId === '') {
    json_fail('Dados invalidos para pagamento com cartao.');
}

function cartao_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);
}

function cartao_corrida_payload_publico(array $pagamento, array $row = []): array
{
    return [
        'id' => $row['id'] ?? null,
        'mp_payment_id' => (string) ($pagamento['id'] ?? $row['mp_payment_id'] ?? ''),
        'status' => mp_status_pagamento_local((string) ($pagamento['status'] ?? $row['status'] ?? 'pendente')),
        'status_mp' => (string) ($pagamento['status'] ?? ''),
        'status_detail' => (string) ($pagamento['status_detail'] ?? ''),
        'external_reference' => (string) ($pagamento['external_reference'] ?? $row['external_reference'] ?? ''),
        'valor_total' => (float) ($row['valor_total'] ?? $pagamento['transaction_amount'] ?? 0),
        'valor_motorista' => (float) ($row['valor_motorista'] ?? 0),
        'valor_plataforma' => (float) ($row['valor_plataforma'] ?? 0),
        'taxa_gateway' => (float) ($row['taxa_gateway'] ?? 0),
        'payment_method_id' => (string) ($pagamento['payment_method_id'] ?? $row['mp_payment_method_id'] ?? ''),
        'gateway_message' => mp_gateway_public_message($pagamento, ''),
    ];
}

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, p.cpf AS passageiro_cpf
         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('Pagamento com cartao 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 !== 'cartao_credito') {
        json_fail('Essa corrida nao foi solicitada com cartao de credito.', 409);
    }

    $mpCustomerId = '';
    $mpCardId = '';
    if ($idCartao > 0) {
        $cartaoStmt = $pdo->prepare(
            'SELECT id, mp_customer_id, mp_card_id, mp_payment_method_id
             FROM passageiro_cartoes
             WHERE id = ?
               AND id_passageiro = ?
               AND ativo = 1
             LIMIT 1'
        );
        $cartaoStmt->execute([$idCartao, $idPassageiro]);
        $cartao = $cartaoStmt->fetch();
        if (!$cartao) {
            json_fail('Cartao salvo nao encontrado para este passageiro.', 404);
        }

        $mpCustomerId = trim((string) ($cartao['mp_customer_id'] ?? ''));
        $mpCardId = trim((string) ($cartao['mp_card_id'] ?? ''));
        if ($paymentMethodId === '') {
            $paymentMethodId = strtolower(trim((string) ($cartao['mp_payment_method_id'] ?? '')));
        }
        if ($mpCustomerId === '' || $mpCardId === '') {
            json_fail('Esse cartao salvo ainda nao esta pronto para cobranca online.', 409);
        }
    }

    if ($paymentMethodId === '') {
        json_fail('Bandeira do cartao nao informada.');
    }

    $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 = "cartao_credito" AND status IN ("pendente", "autorizado", "aprovado"))
         ORDER BY id DESC
         LIMIT 1'
    );
    $existing->execute([$externalReference, $idCorrida]);
    $row = $existing->fetch();
    if ($row && in_array((string) $row['status'], ['autorizado', 'aprovado'], true)) {
        json_ok([
            'pagamento' => cartao_corrida_payload_publico(
                json_decode((string) ($row['raw_response'] ?? ''), true) ?: [],
                $row
            ),
            'busca_iniciada' => (string) $row['status'] === 'aprovado',
        ]);
    }

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

    $payerEmail = trim((string) ($corrida['passageiro_email'] ?? ''));
    if ($payerEmail === '') {
        $payerEmail = 'passageiro' . $idPassageiro . '@bulo.local';
    }
    if ($docNumber === '') {
        $docNumber = preg_replace('/\D+/', '', (string) ($corrida['passageiro_cpf'] ?? ''));
    }

    $payer = [
        'email' => $payerEmail,
    ];
    if ($mpCustomerId !== '') {
        $payer['type'] = 'customer';
        $payer['id'] = $mpCustomerId;
    }

    $request = [
        'transaction_amount' => $valor,
        'token' => $cardToken,
        'description' => 'Bulo - corrida #' . $idCorrida,
        'installments' => $installments,
        'payment_method_id' => $paymentMethodId,
        'external_reference' => $externalReference,
        'capture' => true,
        'payer' => $payer,
    ];
    if ($issuerId !== '') {
        $request['issuer_id'] = $issuerId;
    }
    if ($docNumber !== '') {
        $request['payer']['identification'] = [
            'type' => $docType,
            'number' => $docNumber,
        ];
    }

    $webhookUrl = trim(mp_config_valor($pdo, 'mp_webhook_url'));
    if ($webhookUrl !== '' && !cartao_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-card-' . $idCorrida . '-' . substr(hash('sha256', $cardToken), 0, 16)
    );

    $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, mp_customer_id, mp_card_id, metodo, status,
           valor_total, valor_motorista, valor_plataforma, taxa_gateway, application_fee, raw_request, raw_response)
         VALUES (?, ?, NULL, ?, ?, ?, ?, ?, "cartao_credito", ?, ?, ?, ?, ?, ?, ?, ?)
         ON DUPLICATE KEY UPDATE
           mp_payment_id = VALUES(mp_payment_id),
           mp_customer_id = VALUES(mp_customer_id),
           mp_card_id = VALUES(mp_card_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'
    );
    $requestSeguro = $request;
    $requestSeguro['token'] = '[card_token]';
    $ins->execute([
        $idCorrida,
        $idPassageiro,
        $config['ambiente'],
        $externalReference,
        $mpPaymentId !== '' ? $mpPaymentId : null,
        $mpCustomerId !== '' ? $mpCustomerId : null,
        $mpCardId !== '' ? $mpCardId : null,
        $status,
        $valores['valor_total'],
        $valores['valor_motorista'],
        $valores['valor_plataforma'],
        $valores['taxa_gateway'],
        $valores['application_fee'],
        json_encode($requestSeguro, 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 (mp_column_exists($pdo, 'corridas', 'valor_motorista_liquido')) {
        $sets[] = 'valor_motorista_liquido = ?';
        $params[] = $valores['valor_motorista'];
    }
    if (mp_column_exists($pdo, 'corridas', 'valor_plataforma_bruto')) {
        $sets[] = 'valor_plataforma_bruto = ?';
        $params[] = $valores['valor_plataforma_bruto'];
    }
    if (mp_column_exists($pdo, 'corridas', 'taxa_gateway')) {
        $sets[] = 'taxa_gateway = ?';
        $params[] = $valores['taxa_gateway'];
    }
    if ($sets) {
        $params[] = $idCorrida;
        $up = $pdo->prepare('UPDATE corridas SET ' . implode(', ', $sets) . ' WHERE id = ?');
        $up->execute($params);
    }

    $oferta = null;
    if ($status === 'aprovado') {
        $oferta = corrida_ofertas_despachar($pdo, $idCorrida);
    }

    json_ok([
        'pagamento' => cartao_corrida_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'],
            'mp_payment_method_id' => $paymentMethodId,
            'mp_customer_id' => $mpCustomerId,
            'mp_card_id' => $mpCardId,
            'status' => $status,
        ]),
        'busca_iniciada' => $status === 'aprovado',
        'oferta_id' => $oferta['id'] ?? null,
    ]);
} catch (Throwable $e) {
    json_fail(
        mp_gateway_exception_message($e, 'Erro ao pagar corrida com cartao.'),
        $e instanceof MercadoPagoApiException ? 422 : 500,
        mp_gateway_exception_payload($e)
    );
}
