"""
Orchestrator runner.

run_step(step_name, week_start_date)  — execute one step for all families
run_week(week_start_date)             — execute all steps in sequence
"""
from __future__ import annotations

import logging
from datetime import date, timedelta
from typing import Optional

from app.database import SessionLocal

logger = logging.getLogger(__name__)

STEPS = ("scrape", "generate", "email", "reminder", "deadline", "finalize")


def _current_week_start() -> date:
    """Return the most recent Friday (today if today is Friday)."""
    today = date.today()
    days_since_friday = (today.weekday() - 4) % 7
    return today - timedelta(days=days_since_friday)


def _get_or_create_run(db, family_id, week_start_date: date):
    from app.models import WeeklyRun

    run = (
        db.query(WeeklyRun)
        .filter(
            WeeklyRun.family_id == family_id,
            WeeklyRun.week_start_date == week_start_date,
        )
        .first()
    )
    if run is None:
        run = WeeklyRun(
            family_id=family_id,
            week_start_date=week_start_date,
            status="pending",
        )
        db.add(run)
        db.flush()
        db.refresh(run)
    return run


def run_step(step_name: str, week_start_date: Optional[date] = None) -> None:
    from app.models import FamilyProfile
    from app.services.orchestrator import steps as s

    step_fns = {
        "scrape": s.step_scrape,
        "generate": s.step_generate,
        "email": s.step_email,
        "reminder": s.step_reminder,
        "deadline": s.step_deadline,
        "finalize": s.step_finalize,
    }
    if step_name not in step_fns:
        raise ValueError(f"Unknown step: {step_name!r}. Valid: {list(step_fns)}")

    week = week_start_date or _current_week_start()
    db = SessionLocal()
    try:
        families = db.query(FamilyProfile).all()
        if not families:
            logger.warning("run_step(%s): no family profiles, skipping", step_name)
            return
        for family in families:
            run = _get_or_create_run(db, family.id, week)
            try:
                step_fns[step_name](run, db)
            except Exception:
                logger.exception(
                    "run_step(%s) failed for family %s", step_name, family.id
                )
    finally:
        db.close()


def run_week(week_start_date: Optional[date] = None) -> None:
    week = week_start_date or _current_week_start()
    for step in STEPS:
        run_step(step, week)
