<?php
declare(strict_types=1);

require_once __DIR__ . '/database.php';

const CARTEIRA_TAXA_TOTAL = 0.15;
const CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE = 0.85;
const CARTEIRA_MIN_RESGATE = 25.00;

function carteira_money(float $valor): float
{
    return round($valor, 2);
}

function carteira_column_exists(PDO $pdo, string $table, string $column): bool
{
    static $cache = [];
    $key = $table . '.' . $column;
    if (array_key_exists($key, $cache)) {
        return $cache[$key];
    }

    $stmt = $pdo->prepare(
        'SELECT COUNT(*)
         FROM INFORMATION_SCHEMA.COLUMNS
         WHERE TABLE_SCHEMA = DATABASE()
           AND TABLE_NAME = ?
           AND COLUMN_NAME = ?'
    );
    $stmt->execute([$table, $column]);
    $cache[$key] = (int) $stmt->fetchColumn() > 0;

    return $cache[$key];
}

function carteira_totais_retiradas(int $idMotorista, ?PDO $pdo = null): array
{
    $pdo ??= db();
    $stmt = $pdo->prepare(
        'SELECT
            COALESCE(SUM(CASE WHEN status = "paga" THEN valor ELSE 0 END), 0) AS pago,
            COALESCE(SUM(CASE WHEN status IN ("pendente", "em_processamento") THEN valor ELSE 0 END), 0) AS bloqueado
         FROM carteira_retiradas
         WHERE id_motorista = ?'
    );
    $stmt->execute([$idMotorista]);
    $row = $stmt->fetch() ?: ['pago' => 0, 'bloqueado' => 0];

    return [
        'pago' => carteira_money((float) ($row['pago'] ?? 0)),
        'bloqueado' => carteira_money((float) ($row['bloqueado'] ?? 0)),
    ];
}

function carteira_resumo_motorista(int $idMotorista, ?PDO $pdo = null): array
{
    $pdo ??= db();
    $stmt = $pdo->prepare(
        'SELECT COUNT(*) AS total_corridas,
                COALESCE(SUM(COALESCE(valor, 0)), 0) AS total_bruto,
                COALESCE(SUM(CASE WHEN forma_pagamento = "online" THEN COALESCE(valor, 0) ELSE 0 END), 0) AS total_online,
                COALESCE(SUM(CASE WHEN forma_pagamento = "online" THEN 1 ELSE 0 END), 0) AS corridas_online,
                COALESCE(SUM(CASE WHEN forma_pagamento = "dinheiro" THEN COALESCE(valor, 0) ELSE 0 END), 0) AS total_dinheiro,
                COALESCE(SUM(CASE WHEN forma_pagamento = "dinheiro" THEN 1 ELSE 0 END), 0) AS corridas_dinheiro
         FROM corridas
         WHERE id_motorista = ?
           AND status = "finalizada"'
    );
    $stmt->execute([$idMotorista]);
    $row = $stmt->fetch() ?: [
        'total_corridas' => 0,
        'total_bruto' => 0,
        'total_online' => 0,
        'corridas_online' => 0,
        'total_dinheiro' => 0,
        'corridas_dinheiro' => 0,
    ];

    $totalOnline = (float) ($row['total_online'] ?? 0);
    $totalDinheiro = (float) ($row['total_dinheiro'] ?? 0);
    $totalBruto = (float) ($row['total_bruto'] ?? 0);
    $cancelamentos = ['total_cancelamentos' => 0, 'total_taxas' => 0, 'credito_motorista' => 0];
    if (carteira_column_exists($pdo, 'corridas', 'cancelamento_taxa')) {
        $campoCredito = carteira_column_exists($pdo, 'corridas', 'cancelamento_valor_motorista')
            ? 'COALESCE(cancelamento_valor_motorista, ROUND(COALESCE(cancelamento_taxa, 0) * ' . CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE . ', 2))'
            : 'ROUND(COALESCE(cancelamento_taxa, 0) * ' . CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE . ', 2)';
        $cancelStmt = $pdo->prepare(
            'SELECT COUNT(*) AS total_cancelamentos,
                    COALESCE(SUM(COALESCE(cancelamento_taxa, 0)), 0) AS total_taxas,
                    COALESCE(SUM(' . $campoCredito . '), 0) AS credito_motorista
             FROM corridas
             WHERE id_motorista = ?
               AND status = "cancelada"
               AND COALESCE(cancelamento_taxa, 0) > 0'
        );
        $cancelStmt->execute([$idMotorista]);
        $cancelamentos = $cancelStmt->fetch() ?: $cancelamentos;
    }
    $creditoCancelamentos = carteira_money((float) ($cancelamentos['credito_motorista'] ?? 0));
    $creditoOnline = carteira_money($totalOnline * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE);
    $debitoDinheiro = carteira_money($totalDinheiro * CARTEIRA_TAXA_TOTAL);
    $descontosTotal = carteira_money($totalBruto * CARTEIRA_TAXA_TOTAL);
    $saldoBruto = carteira_money($creditoOnline - $debitoDinheiro + $creditoCancelamentos);
    $retiradas = carteira_totais_retiradas($idMotorista, $pdo);
    $saldoDisponivel = carteira_money($saldoBruto - $retiradas['pago'] - $retiradas['bloqueado']);

    return [
        'saldo' => $saldoDisponivel,
        'saldo_bruto' => $saldoBruto,
        'saldo_disponivel' => $saldoDisponivel,
        'saldo_bloqueado_resgates' => $retiradas['bloqueado'],
        'saldo_pago_resgates' => $retiradas['pago'],
        'situacao' => $saldoDisponivel < 0 ? 'negativo' : ($saldoDisponivel > 0 ? 'positivo' : 'zerado'),
        'taxa_total_percentual' => carteira_money(CARTEIRA_TAXA_TOTAL * 100),
        'percentual_motorista_online' => carteira_money(CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE * 100),
        'minimo_resgate' => CARTEIRA_MIN_RESGATE,
        'resumo' => [
            'total_corridas' => (int) ($row['total_corridas'] ?? 0),
            'total_bruto' => carteira_money($totalBruto),
            'total_online' => carteira_money($totalOnline),
            'corridas_online' => (int) ($row['corridas_online'] ?? 0),
            'credito_online' => $creditoOnline,
            'total_dinheiro' => carteira_money($totalDinheiro),
            'corridas_dinheiro' => (int) ($row['corridas_dinheiro'] ?? 0),
            'debito_dinheiro' => $debitoDinheiro,
            'cancelamentos_taxados' => (int) ($cancelamentos['total_cancelamentos'] ?? 0),
            'cancelamentos_taxas' => carteira_money((float) ($cancelamentos['total_taxas'] ?? 0)),
            'credito_cancelamentos' => $creditoCancelamentos,
            'descontos_total' => $descontosTotal,
        ],
    ];
}

function carteira_extrato_motorista(int $idMotorista, int $limit = 60, ?PDO $pdo = null): array
{
    $pdo ??= db();
    $limit = max(1, min(200, $limit));
    if (carteira_column_exists($pdo, 'corridas', 'cancelamento_taxa')) {
        $campoCredito = carteira_column_exists($pdo, 'corridas', 'cancelamento_valor_motorista')
            ? 'COALESCE(cancelamento_valor_motorista, ROUND(COALESCE(cancelamento_taxa, 0) * ' . CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE . ', 2))'
            : 'ROUND(COALESCE(cancelamento_taxa, 0) * ' . CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE . ', 2)';
        $stmt = $pdo->prepare(
            'SELECT *
             FROM (
                SELECT id, valor, forma_pagamento, finalizada_em AS data_evento, criada_em,
                       "corrida" AS evento_tipo, 0 AS cancelamento_taxa, 0 AS credito_cancelamento
                FROM corridas
                WHERE id_motorista = ?
                  AND status = "finalizada"
                UNION ALL
                SELECT id, COALESCE(cancelamento_taxa, 0) AS valor, "online" AS forma_pagamento,
                       COALESCE(cancelada_em, atualizada_em, criada_em) AS data_evento, criada_em,
                       "cancelamento" AS evento_tipo,
                       COALESCE(cancelamento_taxa, 0) AS cancelamento_taxa,
                       ' . $campoCredito . ' AS credito_cancelamento
                FROM corridas
                WHERE id_motorista = ?
                  AND status = "cancelada"
                  AND COALESCE(cancelamento_taxa, 0) > 0
             ) eventos
             ORDER BY COALESCE(data_evento, criada_em) DESC, id DESC
             LIMIT ' . $limit
        );
        $stmt->execute([$idMotorista, $idMotorista]);
    } else {
        $stmt = $pdo->prepare(
            'SELECT id, valor, forma_pagamento, finalizada_em AS data_evento, criada_em,
                    "corrida" AS evento_tipo, 0 AS cancelamento_taxa, 0 AS credito_cancelamento
             FROM corridas
             WHERE id_motorista = ?
               AND status = "finalizada"
             ORDER BY COALESCE(finalizada_em, criada_em) DESC, id DESC
             LIMIT ' . $limit
        );
        $stmt->execute([$idMotorista]);
    }

    $extrato = [];
    foreach ($stmt->fetchAll() as $corrida) {
        if ((string) ($corrida['evento_tipo'] ?? 'corrida') === 'cancelamento') {
            $credito = carteira_money((float) ($corrida['credito_cancelamento'] ?? 0));
            $taxaCancelamento = carteira_money((float) ($corrida['cancelamento_taxa'] ?? 0));
            $extrato[] = [
                'id_corrida' => (int) $corrida['id'],
                'tipo' => 'credito',
                'forma_pagamento' => 'cancelamento',
                'descricao' => 'Taxa de cancelamento do passageiro',
                'valor_corrida' => $taxaCancelamento,
                'taxa' => carteira_money($taxaCancelamento - $credito),
                'valor_movimentacao' => $credito,
                'data' => $corrida['data_evento'] ?? $corrida['criada_em'],
            ];
            continue;
        }

        $valorCorrida = (float) ($corrida['valor'] ?? 0);
        $formaPagamento = (string) ($corrida['forma_pagamento'] ?? 'dinheiro');
        $taxa = carteira_money($valorCorrida * CARTEIRA_TAXA_TOTAL);
        $isOnline = $formaPagamento === 'online';
        $movimento = $isOnline
            ? carteira_money($valorCorrida * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE)
            : -$taxa;

        $extrato[] = [
            'id_corrida' => (int) $corrida['id'],
            'tipo' => $isOnline ? 'credito' : 'debito',
            'forma_pagamento' => $formaPagamento,
            'descricao' => $isOnline
                ? 'Corrida com pagamento online'
                : 'Taxa da corrida recebida em dinheiro',
            'valor_corrida' => carteira_money($valorCorrida),
            'taxa' => $taxa,
            'valor_movimentacao' => carteira_money($movimento),
            'data' => $corrida['data_evento'] ?? $corrida['criada_em'],
        ];
    }

    return $extrato;
}

function carteira_retiradas_motorista(int $idMotorista, int $limit = 30, ?PDO $pdo = null): array
{
    $pdo ??= db();
    $limit = max(1, min(100, $limit));
    $stmt = $pdo->prepare(
        'SELECT id, valor, saldo_no_pedido, status, pix_tipo, pix_chave, banco_nome,
                banco_agencia, banco_conta, banco_tipo_conta, banco_titular_nome,
                banco_titular_documento, prazo_limite, observacao, solicitado_em,
                processado_por, processado_em
         FROM carteira_retiradas
         WHERE id_motorista = ?
         ORDER BY solicitado_em DESC
         LIMIT ' . $limit
    );
    $stmt->execute([$idMotorista]);

    $rows = [];
    foreach ($stmt->fetchAll() as $row) {
        $row['id'] = (int) $row['id'];
        $row['valor'] = carteira_money((float) $row['valor']);
        $row['saldo_no_pedido'] = carteira_money((float) $row['saldo_no_pedido']);
        $rows[] = $row;
    }

    return $rows;
}

function carteira_auditoria_receitas(?string $inicio = null, ?string $fim = null, ?PDO $pdo = null): array
{
    $pdo ??= db();
    $params = [];
    $periodoSql = '';
    if ($inicio !== null && $fim !== null) {
        $periodoSql = ' AND COALESCE(c.finalizada_em, c.criada_em) >= ? AND COALESCE(c.finalizada_em, c.criada_em) < ?';
        $params = [$inicio, $fim];
    }

    $stmt = $pdo->prepare(
        'SELECT COUNT(*) AS total_corridas,
                COALESCE(SUM(COALESCE(c.valor, 0)), 0) AS receita_total,
                COALESCE(SUM(CASE WHEN c.forma_pagamento = "online" THEN COALESCE(c.valor, 0) ELSE 0 END), 0) AS receita_online,
                COALESCE(SUM(CASE WHEN c.forma_pagamento = "dinheiro" THEN COALESCE(c.valor, 0) ELSE 0 END), 0) AS receita_dinheiro,
                COALESCE(SUM(CASE WHEN c.forma_pagamento = "online" THEN 1 ELSE 0 END), 0) AS corridas_online,
                COALESCE(SUM(CASE WHEN c.forma_pagamento = "dinheiro" THEN 1 ELSE 0 END), 0) AS corridas_dinheiro,
                COALESCE(SUM(CASE WHEN c.id_motorista IS NULL THEN 1 ELSE 0 END), 0) AS corridas_sem_motorista,
                COALESCE(SUM(CASE WHEN COALESCE(c.valor, 0) <= 0 THEN 1 ELSE 0 END), 0) AS corridas_valor_invalido
         FROM corridas c
         WHERE c.status = "finalizada"' . $periodoSql
    );
    $stmt->execute($params);
    $row = $stmt->fetch() ?: [];

    $receitaTotal = carteira_money((float) ($row['receita_total'] ?? 0));
    $receitaOnline = carteira_money((float) ($row['receita_online'] ?? 0));
    $receitaDinheiro = carteira_money((float) ($row['receita_dinheiro'] ?? 0));
    $creditoOnline = carteira_money($receitaOnline * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE);
    $debitoDinheiro = carteira_money($receitaDinheiro * CARTEIRA_TAXA_TOTAL);
    $descontoTotal = carteira_money($receitaTotal * CARTEIRA_TAXA_TOTAL);
    $liquidoMotoristas = carteira_money($receitaTotal * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE);
    $saldoCarteirasBruto = carteira_money($creditoOnline - $debitoDinheiro);

    $checks = [];
    $checks[] = carteira_auditoria_check(
        'Receita total x formas de pagamento',
        $receitaTotal,
        carteira_money($receitaOnline + $receitaDinheiro)
    );
    $checks[] = carteira_auditoria_check(
        'Saldo motoristas dinheiro x 15% dinheiro',
        $debitoDinheiro,
        carteira_money($receitaDinheiro * CARTEIRA_TAXA_TOTAL)
    );
    $checks[] = carteira_auditoria_check(
        'Credito online motorista x 85% online',
        $creditoOnline,
        carteira_money($receitaOnline * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE)
    );
    $checks[] = carteira_auditoria_check(
        'Liquido motoristas x 85% total',
        $liquidoMotoristas,
        carteira_money(($receitaOnline + $receitaDinheiro) * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE)
    );
    $checks[] = carteira_auditoria_check(
        'Desconto total x 15% total',
        $descontoTotal,
        carteira_money(($receitaOnline + $receitaDinheiro) * CARTEIRA_TAXA_TOTAL)
    );

    $motoristasStmt = $pdo->prepare(
        'SELECT c.id_motorista, COALESCE(u.nome, CONCAT("Motorista #", c.id_motorista)) AS motorista_nome,
                COUNT(*) AS corridas,
                COALESCE(SUM(COALESCE(c.valor, 0)), 0) AS total_bruto,
                COALESCE(SUM(CASE WHEN c.forma_pagamento = "online" THEN COALESCE(c.valor, 0) ELSE 0 END), 0) AS total_online,
                COALESCE(SUM(CASE WHEN c.forma_pagamento = "dinheiro" THEN COALESCE(c.valor, 0) ELSE 0 END), 0) AS total_dinheiro
         FROM corridas c
         LEFT JOIN usuarios u ON u.id = c.id_motorista
         WHERE c.status = "finalizada"
           AND c.id_motorista IS NOT NULL' . $periodoSql . '
         GROUP BY c.id_motorista, u.nome
         ORDER BY total_bruto DESC
         LIMIT 80'
    );
    $motoristasStmt->execute($params);

    $motoristas = [];
    foreach ($motoristasStmt->fetchAll() as $motorista) {
        $online = carteira_money((float) $motorista['total_online']);
        $dinheiro = carteira_money((float) $motorista['total_dinheiro']);
        $motoristas[] = [
            'id_motorista' => (int) $motorista['id_motorista'],
            'motorista_nome' => (string) $motorista['motorista_nome'],
            'corridas' => (int) $motorista['corridas'],
            'total_bruto' => carteira_money((float) $motorista['total_bruto']),
            'total_online' => $online,
            'total_dinheiro' => $dinheiro,
            'credito_online' => carteira_money($online * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE),
            'debito_dinheiro' => carteira_money($dinheiro * CARTEIRA_TAXA_TOTAL),
            'saldo_bruto' => carteira_money(($online * CARTEIRA_PERCENTUAL_MOTORISTA_ONLINE) - ($dinheiro * CARTEIRA_TAXA_TOTAL)),
        ];
    }

    return [
        'metricas' => [
            'credito_online_motoristas' => $creditoOnline,
            'debito_dinheiro_motoristas' => $debitoDinheiro,
            'saldo_carteiras_bruto' => $saldoCarteirasBruto,
            'liquido_motoristas' => $liquidoMotoristas,
            'desconto_total' => $descontoTotal,
        ],
        'checks' => $checks,
        'alertas' => [
            'corridas_sem_motorista' => (int) ($row['corridas_sem_motorista'] ?? 0),
            'corridas_valor_invalido' => (int) ($row['corridas_valor_invalido'] ?? 0),
        ],
        'motoristas' => $motoristas,
    ];
}

function carteira_auditoria_check(string $nome, float $esperado, float $obtido): array
{
    $diferenca = carteira_money($obtido - $esperado);

    return [
        'nome' => $nome,
        'esperado' => carteira_money($esperado),
        'obtido' => carteira_money($obtido),
        'diferenca' => $diferenca,
        'ok' => abs($diferenca) <= 0.02,
    ];
}
