"""Coverage business logic."""

from __future__ import annotations

from datetime import datetime, timezone

from sqlalchemy import func, select
from sqlalchemy.orm import Session

from app.models.coverage import Coverage
from app.models.event import Event, EventPhase


def default_phase_status() -> dict[str, str]:
    """Return default phase coverage state."""
    return {phase.value: "not_started" for phase in EventPhase}


def create_initial_coverage(db: Session, engagement_id: int) -> Coverage:
    """Create default coverage row for a new engagement."""
    coverage = Coverage(
        engagement_id=engagement_id,
        phase_status=default_phase_status(),
    )
    db.add(coverage)
    return coverage


def get_coverage_by_engagement_id(db: Session, engagement_id: int) -> Coverage | None:
    """Fetch one coverage row by engagement id."""
    return db.scalar(
        select(Coverage).where(Coverage.engagement_id == engagement_id),
    )


def count_events_by_phase(db: Session, engagement_id: int) -> dict[str, int]:
    """Count events per phase for one engagement."""
    rows = db.execute(
        select(Event.phase, func.count(Event.id))
        .where(Event.engagement_id == engagement_id)
        .group_by(Event.phase),
    ).all()

    counts: dict[str, int] = {}
    for phase, count in rows:
        phase_key = phase.value if isinstance(phase, EventPhase) else str(phase)
        counts[phase_key] = int(count)
    return counts


def phase_status_from_event_counts(event_counts: dict[str, int]) -> dict[str, str]:
    """Map event counts to phase status values."""
    phase_status: dict[str, str] = {}
    for phase in EventPhase:
        phase_key = phase.value
        count = event_counts.get(phase_key, 0)
        if count >= 2:
            phase_status[phase_key] = "done"
        elif count == 1:
            phase_status[phase_key] = "in_progress"
        else:
            phase_status[phase_key] = "not_started"
    return phase_status


def sync_coverage_from_events(db: Session, engagement_id: int) -> Coverage:
    """Recalculate and persist phase coverage from engagement events."""
    coverage = get_coverage_by_engagement_id(db, engagement_id)
    if coverage is None:
        coverage = create_initial_coverage(db, engagement_id)

    event_counts = count_events_by_phase(db, engagement_id)
    coverage.phase_status = phase_status_from_event_counts(event_counts)
    coverage.updated_at = datetime.now(timezone.utc)
    return coverage


def mark_phase_in_progress(db: Session, engagement_id: int, phase: EventPhase) -> Coverage:
    """Switch phase from not_started to in_progress after an event."""
    coverage = get_coverage_by_engagement_id(db, engagement_id)
    if coverage is None:
        coverage = create_initial_coverage(db, engagement_id)

    current_status = dict(coverage.phase_status or default_phase_status())
    phase_key = phase.value

    if current_status.get(phase_key) == "not_started":
        current_status[phase_key] = "in_progress"
        coverage.phase_status = current_status
        coverage.updated_at = datetime.now(timezone.utc)

    return coverage
