"""Utility functions for continuous evaluation."""

from __future__ import annotations

from datetime import UTC, datetime
from fnmatch import fnmatch
from typing import Any

import sqlite3

from logos_adk.cost import DEFAULT_RATES


def utcnow() -> str:
    """Return current UTC timestamp in ISO format."""
    return datetime.now(UTC).isoformat()


def _parse_ts(value: str | None) -> datetime | None:
    """Parse ISO timestamp string."""
    if not value:
        return None
    return datetime.fromisoformat(value)


def _mean(values: list[float], default: float = 0.0) -> float:
    """Calculate mean of values."""
    if not values:
        return default
    return sum(values) / len(values)


def _estimate_cost_usd(model: str | None, usage: dict[str, Any] | None) -> float:
    """Estimate LLM cost in USD."""
    if not model or not usage:
        return 0.0
    input_tokens = int(usage.get("input_tokens", 0) or 0)
    output_tokens = int(usage.get("output_tokens", 0) or 0)
    rates = None
    if model in DEFAULT_RATES:
        rates = DEFAULT_RATES[model]
    else:
        for pattern, candidate in DEFAULT_RATES.items():
            if "*" in pattern and fnmatch(model, pattern):
                rates = candidate
                break
    if rates is None:
        return 0.0
    return round((input_tokens * rates[0] + output_tokens * rates[1]) / 1_000_000, 8)


def _human_quality_score(example: Any) -> float:
    """Calculate human quality score from learning example."""
    values: list[float] = []
    for item in example.feedback:
        if item.kind == "thumbs_up":
            values.append(1.0)
        elif item.kind == "thumbs_down":
            values.append(0.0)
        elif item.kind == "numeric_rating" and item.rating is not None:
            values.append(max(0.0, min(1.0, (float(item.rating) - 1.0) / 4.0)))
        elif item.kind == "edited_answer":
            values.append(0.15)
        elif item.kind == "suggestion":
            values.append(0.8 if item.suggestion_outcome == "accepted" else 0.25)
        if item.failure_types:
            values.append(max(0.0, 1.0 - (0.2 * len(item.failure_types))))
    for item in example.outcomes:
        if item.kind in {"conversion", "resolution"}:
            values.append(1.0 if bool(item.value) else 0.0)
        elif item.kind in {"ctr", "reply_rate"} and isinstance(item.value, (int, float)):
            values.append(max(0.0, min(1.0, float(item.value))))
        elif item.kind in {"escalation", "human_takeover"}:
            values.append(0.0 if bool(item.value) else 1.0)
    return round(_mean(values, default=0.5), 4)


def _quality_rows_summary(rows: list[dict[str, Any]]) -> dict[str, int]:
    """Summarize quality test rows."""
    passed = sum(1 for row in rows if bool(row.get("passed")))
    return {"passed": passed, "failed": len(rows) - passed, "total": len(rows)}


# =============================================================================
# Database helpers
# =============================================================================


def _execute(
    connection: sqlite3.Connection | Any,
    query: str,
    params: tuple[Any, ...] | list[Any],
    use_postgresql: bool,
) -> None:
    """Execute database query."""
    if use_postgresql:
        cursor = connection.cursor()
        cursor.execute(query, params)
    else:
        connection.execute(query, params)


def _fetchone(
    connection: sqlite3.Connection | Any,
    query: str,
    params: tuple[Any, ...] | list[Any],
    use_postgresql: bool,
) -> Any:
    """Fetch one row from database."""
    if use_postgresql:
        cursor = connection.cursor()
        return cursor.execute(query, params).fetchone()
    return connection.execute(query, params).fetchone()


def _fetchall(
    connection: sqlite3.Connection | Any,
    query: str,
    params: tuple[Any, ...] | list[Any],
    use_postgresql: bool,
) -> list[Any]:
    """Fetch all rows from database."""
    if use_postgresql:
        cursor = connection.cursor()
        return cursor.execute(query, params).fetchall()
    return connection.execute(query, params).fetchall()


def _translate_query(query: str) -> str:
    """Translate SQLite query to PostgreSQL."""
    # Basic translation - can be extended
    return query.replace("?", "%s")


def _row_value(row: Any, name: str, index: int) -> Any:
    """Get row value by name or index."""
    if hasattr(row, "get"):
        return row.get(name)
    return row[index] if index < len(row) else None


def _decode_json_field(value: Any, *, default: Any = None) -> Any:
    """Decode JSON field from database."""
    import json

    if value is None:
        return default
    if isinstance(value, (dict, list)):
        return value
    try:
        return json.loads(value)
    except (json.JSONDecodeError, TypeError):
        return default


__all__ = [
    "utcnow",
    "_parse_ts",
    "_mean",
    "_estimate_cost_usd",
    "_human_quality_score",
    "_quality_rows_summary",
    "_execute",
    "_fetchone",
    "_fetchall",
    "_translate_query",
    "_row_value",
    "_decode_json_field",
]
