<?php
declare(strict_types=1);

const MOTORISTA_METRICAS_CORRIDAS_DIAS = 30;

function motorista_metricas_corridas_table_exists(PDO $pdo, string $table): bool
{
    if (function_exists('corrida_table_exists')) {
        return corrida_table_exists($pdo, $table);
    }

    static $cache = [];
    if (array_key_exists($table, $cache)) {
        return $cache[$table];
    }

    try {
        $stmt = $pdo->prepare(
            'SELECT COUNT(*)
             FROM INFORMATION_SCHEMA.TABLES
             WHERE TABLE_SCHEMA = DATABASE()
               AND TABLE_NAME = ?'
        );
        $stmt->execute([$table]);
        $cache[$table] = (int) $stmt->fetchColumn() > 0;
    } catch (Throwable) {
        $cache[$table] = false;
    }

    return $cache[$table];
}

function motorista_metricas_corridas_column_exists(PDO $pdo, string $table, string $column): bool
{
    if (function_exists('corrida_schema_column_exists')) {
        return corrida_schema_column_exists($pdo, $table, $column);
    }

    static $cache = [];
    $key = $table . '.' . $column;
    if (array_key_exists($key, $cache)) {
        return $cache[$key];
    }

    try {
        $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;
    } catch (Throwable) {
        $cache[$key] = false;
    }

    return $cache[$key];
}

function motorista_metricas_corridas_taxa(int $parte, int $total): float
{
    if ($total <= 0) {
        return 0.0;
    }

    return round(($parte / $total) * 100, 2);
}

function motorista_metricas_corridas_vazio(int $idMotorista): array
{
    $periodo = motorista_metricas_corridas_periodo();

    return [
        'id_motorista' => $idMotorista,
        'periodo_dias' => $periodo['dias'],
        'periodo_inicio' => $periodo['inicio'],
        'periodo_fim' => $periodo['fim'],
        'chamadas_recebidas' => 0,
        'chamadas_contabilizadas' => 0,
        'chamadas_aceitas' => 0,
        'chamadas_recusadas' => 0,
        'chamadas_expiradas' => 0,
        'chamadas_canceladas_sistema' => 0,
        'chamadas_pendentes' => 0,
        'corridas_finalizadas' => 0,
        'corridas_canceladas_motorista' => 0,
        'corridas_encerradas_motorista' => 0,
        'taxa_aceitacao' => 0.0,
        'taxa_cancelamento' => 0.0,
    ];
}

function motorista_metricas_corridas_periodo(int $dias = MOTORISTA_METRICAS_CORRIDAS_DIAS): array
{
    $dias = max(1, $dias);
    $fim = new DateTimeImmutable('now');
    $inicio = $fim->sub(new DateInterval('P' . $dias . 'D'));

    return [
        'dias' => $dias,
        'inicio' => $inicio->format('Y-m-d'),
        'fim' => $fim->format('Y-m-d'),
        'inicio_sql' => $inicio->format('Y-m-d H:i:s'),
        'fim_sql' => $fim->format('Y-m-d H:i:s'),
    ];
}

function motorista_metricas_corridas_resumo(PDO $pdo, int $idMotorista, int $dias = MOTORISTA_METRICAS_CORRIDAS_DIAS): array
{
    if ($idMotorista <= 0) {
        return motorista_metricas_corridas_vazio(0);
    }

    $periodo = motorista_metricas_corridas_periodo($dias);
    $metricas = motorista_metricas_corridas_vazio($idMotorista);
    $metricas['periodo_dias'] = $periodo['dias'];
    $metricas['periodo_inicio'] = $periodo['inicio'];
    $metricas['periodo_fim'] = $periodo['fim'];

    if (motorista_metricas_corridas_table_exists($pdo, 'corrida_ofertas')) {
        $stmt = $pdo->prepare(
            'SELECT
                COUNT(*) AS chamadas_recebidas,
                COALESCE(SUM(CASE WHEN status = "aceita" THEN 1 ELSE 0 END), 0) AS chamadas_aceitas,
                COALESCE(SUM(CASE WHEN status = "recusada" THEN 1 ELSE 0 END), 0) AS chamadas_recusadas,
                COALESCE(SUM(CASE WHEN status = "expirada" THEN 1 ELSE 0 END), 0) AS chamadas_expiradas,
                COALESCE(SUM(CASE WHEN status = "cancelada" THEN 1 ELSE 0 END), 0) AS chamadas_canceladas_sistema,
                COALESCE(SUM(CASE WHEN status = "pendente" THEN 1 ELSE 0 END), 0) AS chamadas_pendentes
             FROM corrida_ofertas
             WHERE id_motorista = ?
               AND enviado_em >= ?
               AND enviado_em <= ?'
        );
        $stmt->execute([$idMotorista, $periodo['inicio_sql'], $periodo['fim_sql']]);
        $row = $stmt->fetch() ?: [];
        foreach ([
            'chamadas_recebidas',
            'chamadas_aceitas',
            'chamadas_recusadas',
            'chamadas_expiradas',
            'chamadas_canceladas_sistema',
            'chamadas_pendentes',
        ] as $key) {
            $metricas[$key] = (int) ($row[$key] ?? 0);
        }
    }

    if (motorista_metricas_corridas_table_exists($pdo, 'corridas')) {
        $stmt = $pdo->prepare(
            'SELECT
                COALESCE(SUM(CASE
                    WHEN status = "finalizada"
                     AND COALESCE(finalizada_em, atualizada_em, criada_em) >= ?
                     AND COALESCE(finalizada_em, atualizada_em, criada_em) <= ?
                    THEN 1 ELSE 0 END), 0) AS corridas_finalizadas,
                COALESCE(SUM(CASE
                    WHEN (aceita_em IS NOT NULL OR status IN ("aceita", "aguardando_embarque", "em_andamento", "finalizada", "cancelada"))
                     AND COALESCE(aceita_em, criada_em) >= ?
                     AND COALESCE(aceita_em, criada_em) <= ?
                    THEN 1 ELSE 0 END), 0) AS corridas_aceitas_registradas
             FROM corridas
             WHERE id_motorista = ?'
        );
        $stmt->execute([
            $periodo['inicio_sql'],
            $periodo['fim_sql'],
            $periodo['inicio_sql'],
            $periodo['fim_sql'],
            $idMotorista,
        ]);
        $row = $stmt->fetch() ?: [];
        $metricas['corridas_finalizadas'] = (int) ($row['corridas_finalizadas'] ?? 0);
        $metricas['chamadas_aceitas'] = max(
            $metricas['chamadas_aceitas'],
            (int) ($row['corridas_aceitas_registradas'] ?? 0)
        );
    }

    if (motorista_metricas_corridas_table_exists($pdo, 'corrida_eventos')) {
        $stmt = $pdo->prepare(
            'SELECT COUNT(DISTINCT id_corrida)
             FROM corrida_eventos
             WHERE id_usuario = ?
               AND tipo_usuario = "motorista"
               AND evento = "motorista_aceitou"
               AND criado_em >= ?
               AND criado_em <= ?'
        );
        $stmt->execute([$idMotorista, $periodo['inicio_sql'], $periodo['fim_sql']]);
        $metricas['chamadas_aceitas'] = max(
            $metricas['chamadas_aceitas'],
            (int) $stmt->fetchColumn()
        );
    }

    $cancelamentosMotorista = 0;
    $subqueries = [];
    $params = [];
    if (motorista_metricas_corridas_table_exists($pdo, 'corrida_eventos')) {
        $subqueries[] = 'SELECT id_corrida
                         FROM corrida_eventos
                         WHERE id_usuario = ?
                           AND tipo_usuario = "motorista"
                           AND evento IN ("motorista_cancelou_redistribuida", "motorista_cancelou_definitiva")
                           AND criado_em >= ?
                           AND criado_em <= ?';
        array_push($params, $idMotorista, $periodo['inicio_sql'], $periodo['fim_sql']);
    }
    if (
        motorista_metricas_corridas_table_exists($pdo, 'corridas')
        && motorista_metricas_corridas_column_exists($pdo, 'corridas', 'cancelada_por')
    ) {
        $subqueries[] = 'SELECT id AS id_corrida
                         FROM corridas
                         WHERE id_motorista = ?
                           AND status = "cancelada"
                           AND cancelada_por = "motorista"
                           AND COALESCE(cancelada_em, atualizada_em, criada_em) >= ?
                           AND COALESCE(cancelada_em, atualizada_em, criada_em) <= ?';
        array_push($params, $idMotorista, $periodo['inicio_sql'], $periodo['fim_sql']);
    }
    if ($subqueries) {
        $stmt = $pdo->prepare(
            'SELECT COUNT(DISTINCT id_corrida)
             FROM (' . implode(' UNION ', $subqueries) . ') cancelamentos'
        );
        $stmt->execute($params);
        $cancelamentosMotorista = (int) $stmt->fetchColumn();
    }

    $metricas['corridas_canceladas_motorista'] = $cancelamentosMotorista;
    $metricas['corridas_encerradas_motorista'] = $metricas['corridas_finalizadas'] + $cancelamentosMotorista;
    $metricas['chamadas_contabilizadas'] = $metricas['chamadas_aceitas']
        + $metricas['chamadas_recusadas']
        + $metricas['chamadas_expiradas'];
    $metricas['chamadas_recebidas'] = max(
        $metricas['chamadas_recebidas'],
        $metricas['chamadas_contabilizadas']
    );
    $metricas['taxa_aceitacao'] = motorista_metricas_corridas_taxa(
        $metricas['chamadas_aceitas'],
        $metricas['chamadas_contabilizadas']
    );
    $metricas['taxa_cancelamento'] = motorista_metricas_corridas_taxa(
        $metricas['corridas_canceladas_motorista'],
        $metricas['corridas_encerradas_motorista']
    );

    return $metricas;
}

function motorista_metricas_corridas_persistir(PDO $pdo, array $metricas): void
{
    if (!motorista_metricas_corridas_table_exists($pdo, 'motorista_metricas_corridas')) {
        return;
    }

    $stmt = $pdo->prepare(
        'INSERT INTO motorista_metricas_corridas
          (id_motorista, periodo_dias, periodo_inicio, periodo_fim,
           chamadas_recebidas, chamadas_contabilizadas, chamadas_aceitas,
           chamadas_recusadas, chamadas_expiradas, chamadas_canceladas_sistema, chamadas_pendentes,
           corridas_finalizadas, corridas_canceladas_motorista, corridas_encerradas_motorista,
           taxa_aceitacao, taxa_cancelamento)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
         ON DUPLICATE KEY UPDATE
           periodo_dias = VALUES(periodo_dias),
           periodo_inicio = VALUES(periodo_inicio),
           periodo_fim = VALUES(periodo_fim),
           chamadas_recebidas = VALUES(chamadas_recebidas),
           chamadas_contabilizadas = VALUES(chamadas_contabilizadas),
           chamadas_aceitas = VALUES(chamadas_aceitas),
           chamadas_recusadas = VALUES(chamadas_recusadas),
           chamadas_expiradas = VALUES(chamadas_expiradas),
           chamadas_canceladas_sistema = VALUES(chamadas_canceladas_sistema),
           chamadas_pendentes = VALUES(chamadas_pendentes),
           corridas_finalizadas = VALUES(corridas_finalizadas),
           corridas_canceladas_motorista = VALUES(corridas_canceladas_motorista),
           corridas_encerradas_motorista = VALUES(corridas_encerradas_motorista),
           taxa_aceitacao = VALUES(taxa_aceitacao),
           taxa_cancelamento = VALUES(taxa_cancelamento),
           atualizado_em = CURRENT_TIMESTAMP'
    );
    $stmt->execute([
        (int) $metricas['id_motorista'],
        (int) $metricas['periodo_dias'],
        $metricas['periodo_inicio'],
        $metricas['periodo_fim'],
        (int) $metricas['chamadas_recebidas'],
        (int) $metricas['chamadas_contabilizadas'],
        (int) $metricas['chamadas_aceitas'],
        (int) $metricas['chamadas_recusadas'],
        (int) $metricas['chamadas_expiradas'],
        (int) $metricas['chamadas_canceladas_sistema'],
        (int) $metricas['chamadas_pendentes'],
        (int) $metricas['corridas_finalizadas'],
        (int) $metricas['corridas_canceladas_motorista'],
        (int) $metricas['corridas_encerradas_motorista'],
        (float) $metricas['taxa_aceitacao'],
        (float) $metricas['taxa_cancelamento'],
    ]);
}

function motorista_metricas_corridas_recalcular(PDO $pdo, int $idMotorista, int $dias = MOTORISTA_METRICAS_CORRIDAS_DIAS): array
{
    $metricas = motorista_metricas_corridas_resumo($pdo, $idMotorista, $dias);
    motorista_metricas_corridas_persistir($pdo, $metricas);

    return $metricas;
}

function motorista_metricas_corridas_recalcular_varios(PDO $pdo, array $idsMotoristas): void
{
    $ids = [];
    foreach ($idsMotoristas as $idMotorista) {
        $id = (int) $idMotorista;
        if ($id > 0) {
            $ids[$id] = true;
        }
    }

    foreach (array_keys($ids) as $idMotorista) {
        motorista_metricas_corridas_recalcular($pdo, (int) $idMotorista);
    }
}
