import os
import time
from datetime import datetime, timedelta, timezone
from urllib.parse import urlparse

import psycopg2
from prometheus_client import Gauge, generate_latest, CONTENT_TYPE_LATEST
from wsgiref.simple_server import make_server

TOTAL = Gauge("kyc_monitoring_total", "Total active profiles in monitoring")
STALE = Gauge("kyc_monitoring_stale", "Stale profiles (no refresh within window)")
FRESH = Gauge("kyc_monitoring_fresh", "Fresh profiles (refreshed within window)")
STALE_RATIO = Gauge("kyc_monitoring_stale_ratio", "Stale / total ratio")

_last_fetch_ts = 0.0
_cached_values = None


def _parse_db_url() -> dict:
    db_url = os.getenv("KYC_DATABASE_URL", "").strip()
    if not db_url:
        return {}
    parsed = urlparse(db_url)
    return {
        "host": parsed.hostname,
        "port": parsed.port or 5432,
        "dbname": (parsed.path or "").lstrip("/"),
        "user": parsed.username,
        "password": parsed.password,
        "sslmode": "require" if parsed.scheme.endswith("+ssl") else os.getenv("KYC_DB_SSLMODE", "prefer"),
    }


def _db_params() -> dict:
    params = _parse_db_url()
    if params.get("host"):
        return params
    return {
        "host": os.getenv("KYC_DB_HOST", ""),
        "port": int(os.getenv("KYC_DB_PORT", "5432")),
        "dbname": os.getenv("KYC_DB_NAME", "kyc"),
        "user": os.getenv("KYC_DB_USER", ""),
        "password": os.getenv("KYC_DB_PASSWORD", ""),
        "sslmode": os.getenv("KYC_DB_SSLMODE", "prefer"),
    }


def _fetch_metrics() -> tuple[int, int, int]:
    stale_days = int(os.getenv("KYC_STALE_DAYS", "90"))
    cutoff = datetime.now(timezone.utc) - timedelta(days=stale_days)

    query = """
        SELECT
            COUNT(*) AS total,
            COUNT(*) FILTER (WHERE updated_at IS NULL OR updated_at < %s) AS stale,
            COUNT(*) FILTER (WHERE updated_at IS NOT NULL AND updated_at >= %s) AS fresh
        FROM kyc_monitoring
        WHERE workflow_status = 'active'
    """

    params = _db_params()
    with psycopg2.connect(**params) as conn:
        with conn.cursor() as cur:
            cur.execute(query, (cutoff, cutoff))
            total, stale, fresh = cur.fetchone()
            return int(total), int(stale), int(fresh)


def _get_values() -> tuple[int, int, int]:
    global _last_fetch_ts, _cached_values

    cache_seconds = int(os.getenv("METRICS_CACHE_SECONDS", "60"))
    now_ts = time.time()

    if _cached_values is not None and now_ts - _last_fetch_ts < cache_seconds:
        return _cached_values

    values = _fetch_metrics()
    _cached_values = values
    _last_fetch_ts = now_ts
    return values


def _update_gauges() -> None:
    total, stale, fresh = _get_values()
    TOTAL.set(total)
    STALE.set(stale)
    FRESH.set(fresh)
    ratio = 0.0 if total == 0 else stale / total
    STALE_RATIO.set(ratio)


def app(environ, start_response):
    if environ.get("PATH_INFO", "/") != "/metrics":
        start_response("404 Not Found", [("Content-Type", "text/plain")])
        return [b"not found"]

    _update_gauges()
    data = generate_latest()
    start_response("200 OK", [("Content-Type", CONTENT_TYPE_LATEST)])
    return [data]


def main() -> None:
    bind = os.getenv("METRICS_BIND", "0.0.0.0")
    port = int(os.getenv("METRICS_PORT", "9105"))
    httpd = make_server(bind, port, app)
    httpd.serve_forever()


if __name__ == "__main__":
    main()
