from __future__ import annotations

from collections.abc import Mapping
from typing import Any

from sqlalchemy import select
from sqlalchemy.orm import Session

from services.shared.core import utc_now_iso
from services.shared.sql_models import ReportingInteractionFactRow


_STRING_FIELDS = (
    "interaction_id",
    "channel",
    "queue_id",
    "agent_id",
    "status",
    "created_at",
    "closed_at",
    "source",
)
_BOOL_FIELDS = ("answered", "abandoned", "resolved_first_contact")
_INT_FIELDS = ("wait_seconds", "handle_seconds")


def _clean_string(value: Any) -> str | None:
    raw = str(value or "").strip()
    return raw or None


def _clean_bool(value: Any) -> bool | None:
    if value is None:
        return None
    return bool(value)


def _clean_int(value: Any) -> int | None:
    if value is None or value == "":
        return None
    parsed = int(value)
    return max(parsed, 0)


def normalize_reporting_fact_payload(payload: Mapping[str, Any]) -> dict[str, Any]:
    normalized: dict[str, Any] = {}
    for field in _STRING_FIELDS:
        value = _clean_string(payload.get(field))
        if value is not None:
            normalized[field] = value
    for field in _BOOL_FIELDS:
        value = _clean_bool(payload.get(field))
        if value is not None:
            normalized[field] = value
    for field in _INT_FIELDS:
        value = _clean_int(payload.get(field))
        if value is not None:
            normalized[field] = value
    interaction_id = normalized.get("interaction_id")
    if not interaction_id:
        raise ValueError("interaction_id is required")
    source = normalized.get("source")
    if not source:
        raise ValueError("source is required")
    return normalized


def upsert_reporting_interaction_fact(session: Session, payload: Mapping[str, Any]) -> ReportingInteractionFactRow:
    normalized = normalize_reporting_fact_payload(payload)
    row = session.execute(
        select(ReportingInteractionFactRow).where(
            ReportingInteractionFactRow.interaction_id == normalized["interaction_id"]
        )
    ).scalar_one_or_none()
    if row is None:
        row = ReportingInteractionFactRow(
            interaction_id=normalized["interaction_id"],
            source=normalized["source"],
            updated_at=utc_now_iso(),
        )
        session.add(row)
    for field, value in normalized.items():
        setattr(row, field, value)
    row.updated_at = utc_now_iso()
    return row
