# retoor <retoor@molodetz.nl>

from typing import Annotated
from urllib.parse import quote

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

from devplacepy.database import resolve_object_url
from devplacepy.dependencies import json_or_form
from devplacepy.models import WarJoinForm
from devplacepy.responses import action_result, json_error, respond, wants_json
from devplacepy.schemas import BattlesOut, WarEventsOut, WarOut
from devplacepy.seo import base_seo_context, site_url, website_schema
from devplacepy.services.opinionwar import WarError, rules, store
from devplacepy.utils import get_current_user, not_found, require_user

router = APIRouter()


def _war_error(request: Request, message: str, redirect_url: str):
    if wants_json(request):
        return json_error(400, message)
    separator = "&" if "?" in redirect_url else "?"
    return RedirectResponse(
        url=f"{redirect_url}{separator}error={quote(message)}", status_code=302
    )


def _post_url(war: dict) -> str:
    return resolve_object_url("post", war["post_uid"])


@router.get("", response_class=HTMLResponse)
async def battles_page(
    request: Request, filter: str = "active", search: str = "", page: int = 1
):
    user = get_current_user(request)
    current_filter = filter if filter in store.FILTERS else "active"
    battles, pagination = store.list_wars(
        viewer=user,
        war_filter=current_filter,
        search=search,
        page=max(1, page),
    )
    base = site_url(request)
    seo_ctx = base_seo_context(
        request,
        title="Opinion Wars",
        description=(
            "Week-long faction battles between developers. Pick a side, fight once "
            "a day and carry your faction to victory."
        ),
        breadcrumbs=[
            {"name": "Home", "url": "/feed"},
            {"name": "Battles", "url": "/battles"},
        ],
        schemas=[website_schema(base)],
    )
    return respond(
        request,
        "battles.html",
        {
            **seo_ctx,
            "user": user,
            "battles": battles,
            "current_filter": current_filter,
            "counts": store.filter_counts(user, search),
            "search": search,
            "pagination": pagination,
        },
        model=BattlesOut,
    )


@router.get("/{war_uid}")
async def battle_state(request: Request, war_uid: str):
    user = get_current_user(request)
    serialized = store.get_war_serialized(store.get_war(war_uid), user)
    if not serialized:
        raise not_found("Battle not found")
    return JSONResponse(WarOut.model_validate(serialized).model_dump())


@router.get("/{war_uid}/events")
async def battle_events(
    request: Request, war_uid: str, after: int = 0, limit: int = rules.EVENT_LIMIT_DEFAULT
):
    war = store.resolve_if_due(store.get_war(war_uid))
    if not war:
        raise not_found("Battle not found")
    events = store.events_for(war_uid, after_seq=after, limit=limit)
    return JSONResponse(
        WarEventsOut.model_validate(
            {"events": events, "status": war.get("status") or "active"}
        ).model_dump()
    )


@router.post("/{war_uid}/join")
async def join_battle(
    request: Request,
    war_uid: str,
    data: Annotated[WarJoinForm, Depends(json_or_form(WarJoinForm))],
):
    user = require_user(request)
    war = store.get_war(war_uid)
    if not war:
        raise not_found("Battle not found")
    url = _post_url(war)
    try:
        war = store.join_war(war, user, data.faction, request)
    except WarError as exc:
        return _war_error(request, str(exc), url)
    serialized = store.get_war_serialized(war, user)
    return action_result(request, url, data={"war": serialized})


@router.post("/{war_uid}/fight")
async def fight_battle(request: Request, war_uid: str):
    user = require_user(request)
    war = store.get_war(war_uid)
    if not war:
        raise not_found("Battle not found")
    url = _post_url(war)
    try:
        war, damage = store.fight(war, user, request)
    except WarError as exc:
        return _war_error(request, str(exc), url)
    serialized = store.get_war_serialized(war, user)
    return action_result(request, url, data={"war": serialized, "damage": damage})
