# retoor <retoor@molodetz.nl>

from devplacepy.services.opinionwar import rules

from .._shared import endpoint, field

FILTER_KEYS = ["active", "ended", "mine"]

SAMPLE_WAR = {
    "uid": "0198f2c0-2222-7aaa-8bbb-000000000002",
    "post_uid": "0198f2c0-3333-7aaa-8bbb-000000000003",
    "post_url": "/posts/8bbb000000000003-tabs-or-spaces",
    "post_title": "Tabs or spaces?",
    "faction_a": "Tabs",
    "faction_b": "Spaces",
    "hp_a": 12548,
    "hp_b": 7362,
    "pct_a": 63,
    "pct_b": 37,
    "leader": "a",
    "fighter_count": 42,
    "status": "active",
    "winner": "",
    "ends_at": "2026-08-27T12:00:00+00:00",
    "ends_in": "2d 14h 32m",
    "last_seq": 87,
    "fight_cost": rules.FIGHT_COST_COINS,
    "top_contributors": [
        {"username": "code_warrior", "faction": "a", "hp": 982},
    ],
    "recent_events": [
        {"seq": 87, "kind": "fight", "message": "code_warrior dealt 300 HP for Tabs", "faction": "a"},
    ],
    "viewer": {
        "faction": "a",
        "hp": 256,
        "rank": 7,
        "can_fight": True,
        "next_fight_at": "",
    },
}

GROUP = {
    "slug": "battles",
    "title": "Opinion Wars",
    "intro": f"""
# Opinion Wars

An Opinion War is a week-long two-faction battle attached to a post. The creator names
exactly two factions when creating the post (the `war_faction_a` / `war_faction_b` fields
on `POST /posts/create`); from that moment the battle runs for exactly
{rules.WAR_DURATION_DAYS} days.

Any signed-in member joins one of the two factions and may **fight** once every
{rules.FIGHT_COOLDOWN_HOURS} hours per battle. A fight costs {rules.FIGHT_COST_COINS}
Code Farm coins and deals deterministic, level-weighted damage for the fighter's faction:
`{rules.BASE_DAMAGE} + {rules.LEVEL_DAMAGE_STEP} * min(level, {rules.LEVEL_DAMAGE_CAP})`
HP, so a level 1 member deals {rules.damage_for(1)} HP and the bonus caps at
{rules.damage_for(rules.LEVEL_DAMAGE_CAP)} HP. There is no randomness. Switching factions
is allowed at any time; damage already dealt stays with the faction it was dealt to.

When the week is over the faction with more HP wins. Resolution is evaluated lazily on
read (no background clock): the first read after the deadline freezes the totals, awards
XP (participation for every fighter with at least one fight, a bonus for the winning
side, a bonus for the single top damage dealer) and notifies every fighter. Equal totals
are a draw with participation XP only.

Every battle keeps an ordered event log (kinds `join`, `switch`, `fight`, `lead_change`,
`result`) replayable with the `after` cursor; live frames are also published on the
pub/sub topic `public.battle.{{uid}}`.

All endpoints negotiate HTML or JSON. POST bodies are form encoded. Action POSTs answer
`{{"ok": true, "redirect": "...", "data": {{...}}}}`; a refused action (cooldown, missing
coins, ended battle) answers `400` as `{{"error": {{"status": 400, "message": "..."}}}}`.
""",
    "endpoints": [
        endpoint(
            id="battles-list",
            method="GET",
            path="/battles",
            title="Battle listing",
            summary="Opinion Wars with HP totals, filter counts and the viewer's faction state.",
            auth="public",
            negotiation=True,
            params=[
                field("search", "query", "string", False, "tabs", "Match a faction name or the creator's username."),
                field("filter", "query", "enum", False, "active", "Which battles to list.", options=FILTER_KEYS),
                field("page", "query", "integer", False, "1", "1-based page number."),
            ],
            sample_response={"battles": [SAMPLE_WAR], "counts": {"active": 3, "ended": 12, "mine": 1}},
        ),
        endpoint(
            id="battles-get",
            method="GET",
            path="/battles/{uid}",
            title="Battle state",
            summary="One battle's full serialized state, resolving it first when its week is over.",
            auth="public",
            params=[
                field("uid", "path", "string", True, SAMPLE_WAR["uid"], "Battle uid."),
            ],
            sample_response=SAMPLE_WAR,
        ),
        endpoint(
            id="battles-events",
            method="GET",
            path="/battles/{uid}/events",
            title="Battle events",
            summary="The ordered battle event log, replayable incrementally with the after cursor.",
            auth="public",
            params=[
                field("uid", "path", "string", True, SAMPLE_WAR["uid"], "Battle uid."),
                field("after", "query", "integer", False, "0", "Return only events with a seq greater than this."),
                field("limit", "query", "integer", False, "500", "Maximum events to return."),
            ],
            sample_response={"events": SAMPLE_WAR["recent_events"], "status": "active"},
        ),
        endpoint(
            id="battles-join",
            method="POST",
            path="/battles/{uid}/join",
            title="Join or switch faction",
            summary="Join faction a or b, or switch an existing fighter to the other side.",
            auth="user",
            encoding="form",
            params=[
                field("uid", "path", "string", True, SAMPLE_WAR["uid"], "Battle uid."),
                field("faction", "form", "enum", True, "a", "Which side to join or switch to.", options=["a", "b"]),
            ],
            sample_response={"ok": True, "redirect": SAMPLE_WAR["post_url"], "data": {"war": SAMPLE_WAR}},
        ),
        endpoint(
            id="battles-fight",
            method="POST",
            path="/battles/{uid}/fight",
            title="Fight",
            summary=(
                f"Spend {rules.FIGHT_COST_COINS} Code Farm coins and deal level-weighted HP damage "
                f"for your faction. Once per {rules.FIGHT_COOLDOWN_HOURS} hours per battle."
            ),
            auth="user",
            encoding="form",
            params=[
                field("uid", "path", "string", True, SAMPLE_WAR["uid"], "Battle uid."),
            ],
            sample_response={"ok": True, "redirect": SAMPLE_WAR["post_url"], "data": {"war": SAMPLE_WAR, "damage": 300}},
        ),
    ],
}
