<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Metrics;

use PDO;

/**
 * Contadores agregados por proceso (archivo + bloqueo). Sirve para inspección vía GET /metrics.
 */
final class MetricsRegistry
{
    private static ?PDO $pdo = null;
    private const DB_TABLE = 'auth.metrics_minute';

    public static function setPdo(?PDO $pdo): void
    {
        self::$pdo = $pdo;
    }

    public static function record(int $status, float $durationMs): void
    {
        if (self::$pdo === null) {
            return;
        }
        self::recordDb($status, $durationMs);
    }

    private static function recordDb(int $status, float $durationMs): void
    {
        try {
            $sql = 'INSERT INTO ' . self::DB_TABLE . ' (
                        bucket, requests_total, responses_2xx, responses_4xx, responses_5xx, latency_sum_ms, latency_count, updated_at
                    ) VALUES (
                        date_trunc(\'minute\', now()), 1,
                        CASE WHEN ? BETWEEN 200 AND 299 THEN 1 ELSE 0 END,
                        CASE WHEN ? BETWEEN 400 AND 499 THEN 1 ELSE 0 END,
                        CASE WHEN ? BETWEEN 500 AND 599 THEN 1 ELSE 0 END,
                        ?, 1, now()
                    )
                    ON CONFLICT (bucket) DO UPDATE SET
                        requests_total = ' . self::DB_TABLE . '.requests_total + EXCLUDED.requests_total,
                        responses_2xx = ' . self::DB_TABLE . '.responses_2xx + EXCLUDED.responses_2xx,
                        responses_4xx = ' . self::DB_TABLE . '.responses_4xx + EXCLUDED.responses_4xx,
                        responses_5xx = ' . self::DB_TABLE . '.responses_5xx + EXCLUDED.responses_5xx,
                        latency_sum_ms = ' . self::DB_TABLE . '.latency_sum_ms + EXCLUDED.latency_sum_ms,
                        latency_count = ' . self::DB_TABLE . '.latency_count + EXCLUDED.latency_count,
                        updated_at = now()';
            $stmt = self::$pdo->prepare($sql);
            $stmt->execute([$status, $status, $status, $durationMs]);
        } catch (\Throwable) {
            // no-op
        }
    }

    /** @return array<string, mixed> */
    public static function snapshot(): array
    {
        if (self::$pdo === null) {
            return [
                'enabled' => true,
                'backend' => 'postgres',
                'error' => 'database_not_initialized',
                'counters' => [
                    'requests_total' => 0,
                    'responses_2xx' => 0,
                    'responses_4xx' => 0,
                    'responses_5xx' => 0,
                ],
                'latency_ms' => ['avg' => null, 'count' => 0],
            ];
        }
        return self::snapshotDb();
    }

    /** @return array<string, mixed> */
    private static function snapshotDb(): array
    {
        try {
            $row = self::$pdo->query(
                'SELECT
                    COALESCE(SUM(requests_total), 0) AS requests_total,
                    COALESCE(SUM(responses_2xx), 0) AS responses_2xx,
                    COALESCE(SUM(responses_4xx), 0) AS responses_4xx,
                    COALESCE(SUM(responses_5xx), 0) AS responses_5xx,
                    COALESCE(SUM(latency_sum_ms), 0) AS latency_sum_ms,
                    COALESCE(SUM(latency_count), 0) AS latency_count,
                    MAX(updated_at) AS updated_at
                 FROM ' . self::DB_TABLE,
            )->fetch();

            $n = (int) ($row['latency_count'] ?? 0);
            $sum = (float) ($row['latency_sum_ms'] ?? 0);

            return [
                'enabled' => true,
                'backend' => 'postgres',
                'updated_at' => $row['updated_at'] ?? null,
                'counters' => [
                    'requests_total' => (int) ($row['requests_total'] ?? 0),
                    'responses_2xx' => (int) ($row['responses_2xx'] ?? 0),
                    'responses_4xx' => (int) ($row['responses_4xx'] ?? 0),
                    'responses_5xx' => (int) ($row['responses_5xx'] ?? 0),
                ],
                'latency_ms' => [
                    'avg' => $n > 0 ? round($sum / $n, 3) : null,
                    'count' => $n,
                ],
            ];
        } catch (\Throwable) {
            return [
                'enabled' => true,
                'backend' => 'postgres',
                'error' => 'query_failed',
                'counters' => [
                    'requests_total' => 0,
                    'responses_2xx' => 0,
                    'responses_4xx' => 0,
                    'responses_5xx' => 0,
                ],
                'latency_ms' => ['avg' => null, 'count' => 0],
            ];
        }
    }
}
