"""Cloudflare Analytics Engine reader for generated-app traffic telemetry.

This module deliberately returns raw project totals only. Core resolves project
ownership before persisting data, so Cloudflare analytics never becomes an
authorization or billing source of truth.
"""
from __future__ import annotations

import re
from datetime import date, timedelta
from uuid import UUID

import httpx
import structlog

from src.config import get_settings

logger = structlog.get_logger()

_DATASET_RE = re.compile(r"^[A-Za-z0-9_]+$")


def parse_hosted_app_usage_rows(payload: object) -> dict[UUID, dict[str, int]]:
    """Parse Analytics Engine JSON defensively, ignoring malformed dimensions."""
    if not isinstance(payload, dict):
        return {}
    rows = payload.get("data")
    if not isinstance(rows, list):
        result = payload.get("result")
        rows = result.get("data") if isinstance(result, dict) else result
    if not isinstance(rows, list):
        return {}

    usage: dict[UUID, dict[str, int]] = {}
    for row in rows:
        if not isinstance(row, dict):
            continue
        try:
            project_id = UUID(str(row.get("project_id") or row.get("blob1") or ""))
        except ValueError:
            continue
        try:
            requests = max(0, int(float(row.get("hosted_app_requests", 0))))
            egress_bytes = max(0, int(float(row.get("hosted_app_egress_bytes", 0))))
        except (TypeError, ValueError):
            continue
        usage[project_id] = {
            "hosted_app_requests": requests,
            "hosted_app_egress_bytes": egress_bytes,
        }
    return usage


async def fetch_hosted_app_usage_by_project(snapshot_date: date) -> dict[UUID, dict[str, int]]:
    """Return a prior UTC day's production hosted-app requests and response bytes."""
    settings = get_settings()
    token = settings.cloudflare_analytics_api_token or settings.cloudflare_api_token
    dataset = settings.hosting_usage_analytics_dataset.strip()
    if not settings.cloudflare_account_id or not token or not _DATASET_RE.fullmatch(dataset):
        logger.info("hosted_app_usage_unconfigured")
        return {}

    next_day = snapshot_date + timedelta(days=1)
    query = f"""
SELECT
  blob1 AS project_id,
  SUM(_sample_interval) AS hosted_app_requests,
  SUM(_sample_interval * double2) AS hosted_app_egress_bytes
FROM {dataset}
WHERE timestamp >= '{snapshot_date.isoformat()} 00:00:00'
  AND timestamp < '{next_day.isoformat()} 00:00:00'
GROUP BY blob1
FORMAT JSON
"""
    url = (
        "https://api.cloudflare.com/client/v4/accounts/"
        f"{settings.cloudflare_account_id}/analytics_engine/sql"
    )
    try:
        async with httpx.AsyncClient(timeout=20) as client:
            response = await client.post(
                url,
                headers={
                    "Authorization": f"Bearer {token}",
                    "Content-Type": "text/plain",
                },
                content=query,
            )
            response.raise_for_status()
            usage = parse_hosted_app_usage_rows(response.json())
    except (httpx.HTTPError, ValueError) as exc:
        logger.warning(
            "hosted_app_usage_fetch_error",
            snapshot_date=str(snapshot_date),
            error=str(exc),
        )
        return {}

    logger.info(
        "hosted_app_usage_fetched",
        snapshot_date=str(snapshot_date),
        projects=len(usage),
    )
    return usage
