from __future__ import annotations

from datetime import datetime, timezone

from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse

from app_dependencies import get_runtime
from card_store import (
    delete_card,
    load_card,
    load_cards,
    normalize_card_id,
    parse_iso_datetime,
    write_card,
)
from route_helpers import read_json_request
from session_store import normalize_session_chat_id
from web_runtime import WebAppRuntime

router = APIRouter()


@router.get("/cards")
async def get_cards(request: Request) -> JSONResponse:
    chat_id = normalize_session_chat_id(str(request.query_params.get("chat_id", "web") or "web"))
    if not chat_id:
        return JSONResponse({"error": "invalid chat id"}, status_code=400)
    return JSONResponse(load_cards(chat_id))


@router.delete("/cards/{card_id}")
async def delete_card_route(
    card_id: str,
    runtime: WebAppRuntime = Depends(get_runtime),
) -> JSONResponse:
    if not normalize_card_id(card_id):
        return JSONResponse({"error": "invalid card id"}, status_code=400)
    card = load_card(card_id)
    delete_card(card_id)
    await runtime.publish_cards_changed(card.get("chat_id") if isinstance(card, dict) else None)
    return JSONResponse({"status": "ok"})


@router.post("/cards/{card_id}/snooze")
async def snooze_card(
    card_id: str,
    request: Request,
    runtime: WebAppRuntime = Depends(get_runtime),
) -> JSONResponse:
    if not normalize_card_id(card_id):
        return JSONResponse({"error": "invalid card id"}, status_code=400)

    try:
        payload = await read_json_request(request)
    except ValueError as exc:
        return JSONResponse({"error": str(exc)}, status_code=400)

    until_raw = str(payload.get("until", "")).strip()
    until_dt = parse_iso_datetime(until_raw)
    if until_dt is None:
        return JSONResponse({"error": "until must be a valid ISO datetime"}, status_code=400)

    card = load_card(card_id)
    if card is None:
        return JSONResponse({"error": "card not found"}, status_code=404)

    card["snooze_until"] = until_dt.isoformat()
    card["updated_at"] = datetime.now(timezone.utc).isoformat()
    persisted = write_card(card)
    if persisted is None:
        return JSONResponse({"error": "failed to snooze card"}, status_code=500)
    await runtime.publish_cards_changed(persisted.get("chat_id"))
    return JSONResponse({"status": "ok", "card": persisted})


@router.post("/cards/{card_id}/state")
async def update_card_state(
    card_id: str,
    request: Request,
    runtime: WebAppRuntime = Depends(get_runtime),
) -> JSONResponse:
    if not normalize_card_id(card_id):
        return JSONResponse({"error": "invalid card id"}, status_code=400)

    try:
        payload = await read_json_request(request)
    except ValueError as exc:
        return JSONResponse({"error": str(exc)}, status_code=400)

    template_state = payload.get("template_state")
    if not isinstance(template_state, dict):
        return JSONResponse({"error": "template_state must be an object"}, status_code=400)

    card = load_card(card_id)
    if card is None:
        return JSONResponse({"error": "card not found"}, status_code=404)

    if str(card.get("kind", "")) != "text":
        return JSONResponse({"error": "only text cards support template_state"}, status_code=400)

    card["template_state"] = template_state
    card["updated_at"] = datetime.now(timezone.utc).isoformat()
    persisted = write_card(card)
    if persisted is None:
        return JSONResponse({"error": "failed to update card state"}, status_code=500)
    await runtime.publish_cards_changed(persisted.get("chat_id"))
    return JSONResponse({"status": "ok", "card": persisted})
