<?php

namespace Modules\APIPublica\Services;

use PDO;
use Exception;

/**
 * Serviço para controle de rate limiting
 */
class RateLimitService {
    private PDO $pdo;
    private string $tenantId;

    public function __construct(string $tenantId) {
        $this->tenantId = $tenantId;
        $this->pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);
    }

    /**
     * Verifica se requisição está dentro do rate limit
     */
    public function verificar(string $identificador, ?int $apiKeyId = null, ?int $limiteMinuto = null, ?int $limiteHora = null): bool {
        // Buscar ou criar registro de rate limit
        $stmt = $this->pdo->prepare('
            SELECT * FROM api_rate_limits
            WHERE tenant_id = ? AND identificador = ?
        ');
        $stmt->execute([$this->tenantId, $identificador]);
        $rateLimit = $stmt->fetch(PDO::FETCH_ASSOC);

        $agora = time();
        $resetMinuto = $agora + 60;
        $resetHora = $agora + 3600;
        $resetDia = strtotime('tomorrow');

        if (!$rateLimit) {
            // Criar novo registro
            $stmt = $this->pdo->prepare('
                INSERT INTO api_rate_limits (
                    tenant_id, api_key_id, identificador,
                    requests_minuto, requests_hora, requests_dia,
                    reset_minuto, reset_hora, reset_dia
                ) VALUES (?, ?, ?, 1, 1, 1, FROM_UNIXTIME(?), FROM_UNIXTIME(?), FROM_UNIXTIME(?))
            ');
            $stmt->execute([
                $this->tenantId,
                $apiKeyId,
                $identificador,
                $resetMinuto,
                $resetHora,
                $resetDia
            ]);
            return true;
        }

        // Verificar se precisa resetar contadores
        $resetMinutoTimestamp = strtotime($rateLimit['reset_minuto']);
        $resetHoraTimestamp = strtotime($rateLimit['reset_hora']);
        $resetDiaTimestamp = strtotime($rateLimit['reset_dia']);

        $requestsMinuto = (int)$rateLimit['requests_minuto'];
        $requestsHora = (int)$rateLimit['requests_hora'];
        $requestsDia = (int)$rateLimit['requests_dia'];

        // Resetar se necessário
        if ($agora >= $resetMinutoTimestamp) {
            $requestsMinuto = 0;
            $resetMinuto = $agora + 60;
        }
        if ($agora >= $resetHoraTimestamp) {
            $requestsHora = 0;
            $resetHora = $agora + 3600;
        }
        if ($agora >= $resetDiaTimestamp) {
            $requestsDia = 0;
            $resetDia = strtotime('tomorrow');
        }

        // Buscar limites da API key se fornecida
        if ($apiKeyId) {
            $stmt = $this->pdo->prepare('SELECT rate_limit_por_minuto, rate_limit_por_hora FROM api_keys WHERE id = ?');
            $stmt->execute([$apiKeyId]);
            $apiKey = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($apiKey) {
                $limiteMinuto = $limiteMinuto ?? (int)$apiKey['rate_limit_por_minuto'];
                $limiteHora = $limiteHora ?? (int)$apiKey['rate_limit_por_hora'];
            }
        }

        // Limites padrão
        $limiteMinuto = $limiteMinuto ?? 60;
        $limiteHora = $limiteHora ?? 1000;
        $limiteDia = 10000;

        // Verificar limites
        if ($requestsMinuto >= $limiteMinuto) {
            return false; // Rate limit excedido por minuto
        }
        if ($requestsHora >= $limiteHora) {
            return false; // Rate limit excedido por hora
        }
        if ($requestsDia >= $limiteDia) {
            return false; // Rate limit excedido por dia
        }

        // Incrementar contadores
        $stmt = $this->pdo->prepare('
            UPDATE api_rate_limits
            SET requests_minuto = ?,
                requests_hora = ?,
                requests_dia = ?,
                reset_minuto = FROM_UNIXTIME(?),
                reset_hora = FROM_UNIXTIME(?),
                reset_dia = FROM_UNIXTIME(?)
            WHERE id = ?
        ');
        $stmt->execute([
            $requestsMinuto + 1,
            $requestsHora + 1,
            $requestsDia + 1,
            $resetMinuto,
            $resetHora,
            $resetDia,
            $rateLimit['id']
        ]);

        return true;
    }

    /**
     * Registra uso da API
     */
    public function registrarUso(?int $apiKeyId, string $endpoint, string $metodo, int $statusCode, ?int $tempoResposta = null, ?string $ip = null): void {
        $stmt = $this->pdo->prepare('
            INSERT INTO api_usage_logs (
                tenant_id, api_key_id, endpoint, metodo,
                status_code, tempo_resposta_ms, ip_address
            ) VALUES (?, ?, ?, ?, ?, ?, ?)
        ');
        $stmt->execute([
            $this->tenantId,
            $apiKeyId,
            $endpoint,
            $metodo,
            $statusCode,
            $tempoResposta,
            $ip
        ]);
    }
}

