from __future__ import annotations

from datetime import datetime, timezone
from typing import Iterable, List, Tuple
from uuid import UUID

from ..models import SaaSEvent
from ..repos.saas_event_repo import (
    SaaSEventFailure,
    SaaSEventRepo,
    SaaSEventSummary,
)
from ..telemetry.schemas import SaaSEventPayload


def _coerce_uuid(value: str | UUID | None) -> UUID | None:
    if value is None or value == "":
        return None
    if isinstance(value, UUID):
        return value
    return UUID(str(value))


def _normalize_ts(ts: datetime) -> datetime:
    if ts.tzinfo is None:
        return ts.replace(tzinfo=timezone.utc)
    return ts.astimezone(timezone.utc)


class SaaSEventService:
    """Business logic around SaaS event ingestion and reporting."""

    def __init__(self, repo: SaaSEventRepo):
        self.repo = repo

    async def ingest_batch(
        self, payloads: Iterable[SaaSEventPayload]
    ) -> Tuple[int, int]:
        events: List[SaaSEvent] = []
        for payload in payloads:
            event_kwargs = {
                "ts": _normalize_ts(payload.ts),
                "org_id": payload.org_id,
                "user_email": str(payload.user_email),
                "sheet_id": payload.sheet_id,
                "tab_name": payload.tab_name,
                "source_version": payload.source_version,
                "source": payload.source or "sheets_addon",
                "action": payload.action,
                "status": payload.status,
                "rows": payload.rows,
                "duration_ms": payload.duration_ms,
                "credits_delta": payload.credits_delta,
                "job_id": payload.job_id,
                "idempotency_key": payload.idempotency_key,
                "attrs": dict(payload.attrs or {}),
            }
            coerced_id = _coerce_uuid(payload.id)
            if coerced_id is not None:
                event_kwargs["id"] = coerced_id

            events.append(SaaSEvent(**event_kwargs))

        return await self.repo.record_batch(events)

    async def summary(
        self, org_id: str, *, since: datetime | None = None, actions_limit: int = 5
    ) -> SaaSEventSummary:
        return await self.repo.summary(org_id, since=since, actions_limit=actions_limit)

    async def recent_failures(
        self,
        org_id: str,
        *,
        since: datetime | None = None,
        action: str | None = None,
        limit: int = 50,
    ) -> List[SaaSEventFailure]:
        return await self.repo.recent_failures(
            org_id, since=since, action=action, limit=limit
        )

    async def daily_rollup(self, org_id: str, *, days: int = 30) -> List[dict]:
        return await self.repo.daily_rollup(org_id, days=days)
