"""When a form takes new submissions — FormSettings.schedule (app/schemas/
workflow.py::FormSchedule): from opens_at until closes_at, unless paused or
archived.

Checked by app/routers/form_submissions.py when a submission is created
(a draft too) and when a draft is submitted, for signed-in and public
submissions alike. Not checked when an existing submission is edited or
corrected — an application returned for correction can be resubmitted
after the form has closed."""

from datetime import datetime, timezone

from fastapi import HTTPException

from app.models.workflow import Form

OPEN = "open"
_DEFAULTS = {
    "scheduled": "This form isn't open yet.",
    "paused": "This form is paused for now — please check back later.",
    "closed": "This form is closed and no longer takes submissions.",
    "archived": "This form is closed and no longer takes submissions.",
}


def _when(value) -> datetime | None:
    if value in (None, ""):
        return None
    if isinstance(value, datetime):
        moment = value
    else:
        try:
            moment = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
        except ValueError:
            return None
    return moment if moment.tzinfo else moment.replace(tzinfo=timezone.utc)


def window(settings: dict | None) -> tuple[datetime | None, datetime | None]:
    schedule = (settings or {}).get("schedule") or {}
    return _when(schedule.get("opens_at")), _when(schedule.get("closes_at"))


def availability(settings: dict | None, now: datetime | None = None) -> tuple[str, str | None]:
    """("open", None), or (why not — scheduled / paused / closed / archived,
    the line to show)."""
    schedule = (settings or {}).get("schedule") or {}
    now = now or datetime.now(timezone.utc)
    opens, closes = window(settings)
    if schedule.get("archived"):
        state = "archived"
    elif schedule.get("paused"):
        state = "paused"
    elif opens and now < opens:
        state = "scheduled"
    elif closes and now >= closes:
        state = "closed"
    else:
        return OPEN, None
    message = (schedule.get("message") or "").strip() or _DEFAULTS[state]
    if state == "scheduled" and not (schedule.get("message") or "").strip():
        message = f"This form opens on {opens.strftime('%d %b %Y, %H:%M')} UTC."
    return state, message


def ensure_open(form: Form) -> None:
    """409 with the form's own line when it isn't taking submissions."""
    state, message = availability(form.settings)
    if state != OPEN:
        raise HTTPException(status_code=409, detail=message)
