# retoor <retoor@molodetz.nl>

from __future__ import annotations

from devplacepy.database import get_table, get_users_by_uids
from devplacepy.utils import generate_uid

from .. import economy
from .common import (
    GameError,
    _farms,
    _iso,
    _lvl,
    _now,
    _update_farm,
    conditional_update_farm,
)


def _eras():
    return get_table("game_eras")


def _era_results():
    return get_table("game_era_results")


def active_era() -> dict | None:
    return _eras().find_one(active=1)


def active_era_name() -> str | None:
    era = active_era()
    return era["name"] if era else None


def start_era(name: str, duration_days: int) -> dict:
    if active_era():
        raise GameError("An Era is already running.")
    now = _now()
    ends_at = now.replace(microsecond=0)
    from datetime import timedelta

    ends_at = ends_at + timedelta(days=max(1, duration_days))
    last = list(_eras().find(order_by=["-era_number"]))
    era_number = (int(last[0]["era_number"]) + 1) if last else 1
    row = {
        "uid": generate_uid(),
        "era_number": era_number,
        "name": name,
        "started_at": _iso(now),
        "ends_at": _iso(ends_at),
        "active": 1,
        "created_at": _iso(now),
    }
    _eras().insert(row)
    now_iso = _iso(now)
    for farm in _farms().find():
        _update_farm(
            farm["uid"],
            {"era_coins": 0, "era_harvests": 0, "era_joined_at": now_iso},
        )
    return row


def _era_participants() -> list[dict]:
    return [f for f in _farms().find() if _lvl(f, "era_coins") or _lvl(f, "era_harvests")]


def end_era() -> dict:
    era = active_era()
    if not era:
        raise GameError("No Era is currently running.")
    farms = _era_participants()
    ranked = sorted(
        farms,
        key=lambda f: economy.era_score(
            _lvl(f, "era_coins"), _lvl(f, "era_harvests"), _lvl(f, "prestige")
        ),
        reverse=True,
    )
    now = _iso(_now())
    from .cosmetics import _cosmetics

    era_cosmetics = [c for c in economy.COSMETICS if c.era_key == era["name"]]
    for rank, farm in enumerate(ranked, start=1):
        stars_award = economy.era_reward_stars(rank)
        reward_cosmetic_key = ""
        if stars_award and era_cosmetics:
            reward_cosmetic_key = era_cosmetics[(rank - 1) % len(era_cosmetics)].key
            if not _cosmetics().find_one(
                user_uid=farm["user_uid"], cosmetic_key=reward_cosmetic_key
            ):
                _cosmetics().insert(
                    {
                        "uid": generate_uid(),
                        "user_uid": farm["user_uid"],
                        "cosmetic_key": reward_cosmetic_key,
                        "purchased_at": now,
                        "created_at": now,
                    }
                )
        if stars_award:
            conditional_update_farm(
                farm["uid"],
                "stars = COALESCE(stars, 0) + :award",
                "1 = 1",
                {"award": stars_award},
            )
        _update_farm(farm["uid"], {"era_coins": 0, "era_harvests": 0})
        _era_results().insert(
            {
                "uid": generate_uid(),
                "era_number": era["era_number"],
                "user_uid": farm["user_uid"],
                "rank": rank,
                "era_score": economy.era_score(
                    _lvl(farm, "era_coins"), _lvl(farm, "era_harvests"), _lvl(farm, "prestige")
                ),
                "era_coins_final": _lvl(farm, "era_coins"),
                "joined_at": farm.get("era_joined_at") or "",
                "reward_stars": stars_award,
                "reward_cosmetic_key": reward_cosmetic_key,
                "created_at": now,
            }
        )
    _eras().update({"uid": era["uid"], "active": 0}, ["uid"])
    return {"era_number": era["era_number"], "participants": len(ranked)}


def leaderboard_era(limit: int = 25) -> list[dict]:
    era = active_era()
    if not era:
        return []
    farms = sorted(
        _era_participants(),
        key=lambda f: economy.era_score(
            _lvl(f, "era_coins"), _lvl(f, "era_harvests"), _lvl(f, "prestige")
        ),
        reverse=True,
    )[:limit]
    if not farms:
        return []
    users = get_users_by_uids([f["user_uid"] for f in farms])
    entries = []
    for rank, farm in enumerate(farms, start=1):
        owner = users.get(farm["user_uid"])
        if not owner:
            continue
        entries.append(
            {
                "rank": rank,
                "username": owner.get("username", ""),
                "level": int(farm.get("level", 1)),
                "xp": int(farm.get("xp", 0)),
                "coins": int(farm.get("coins", 0)),
                "total_harvests": int(farm.get("total_harvests", 0)),
                "prestige": int(farm.get("prestige") or 0),
                "score": economy.era_score(
                    _lvl(farm, "era_coins"), _lvl(farm, "era_harvests"), _lvl(farm, "prestige")
                ),
                "title": economy.cosmetic_title_name(farm.get("active_title") or ""),
            }
        )
    return entries
