from dataclasses import dataclass, field
from typing import Optional


@dataclass
class JudgementCounts:
    perfect: int = 0
    good: int = 0
    ok: int = 0
    miss: int = 0

    @classmethod
    def from_dict(cls, data: dict) -> "JudgementCounts":
        return cls(
            perfect=data.get("perfect", 0),
            good=data.get("good", 0),
            ok=data.get("ok", 0),
            miss=data.get("miss", 0),
        )


@dataclass
class Score:
    score_id: str           # sid
    beatmap_id: str         # bid
    beatmap_title: str      # bt
    beatmap_artist: str     # ba
    difficulty: str         # diff
    pp: float
    accuracy: float         # acc
    score: int              # sc
    max_combo: int          # cb
    grade: str              # gr
    mods: list[str]
    played_at: str          # at
    perfect: int            # pf  (not always present)
    good: int               # gd
    ok: int                 # ok
    miss: int               # ms
    star_rating: float      # sr
    length: float           # len
    od: float
    bpm: int
    mapper_name: str        # mn  (not always present)

    @classmethod
    def from_dict(cls, data: dict) -> "Score":
        return cls(
            score_id=data.get("sid", ""),
            beatmap_id=data.get("bid", ""),
            beatmap_title=data.get("bt", ""),
            beatmap_artist=data.get("ba", ""),
            difficulty=data.get("diff", ""),
            pp=data.get("pp", 0.0),
            accuracy=data.get("acc", 0.0),
            score=data.get("sc", 0),
            max_combo=data.get("cb", 0),
            grade=data.get("gr", ""),
            mods=data.get("mods", []),
            played_at=data.get("at", ""),
            perfect=data.get("pf", 0),
            good=data.get("gd", 0),
            ok=data.get("ok", 0),
            miss=data.get("ms", 0),
            star_rating=data.get("sr", 0.0),
            length=data.get("len", 0.0),
            od=data.get("od", 0.0),
            bpm=data.get("bpm", 0),
            mapper_name=data.get("mn", ""),
        )


@dataclass
class LeaderboardScore:
    """Score as returned by beatmap leaderboard endpoint"""
    rank: int
    score_id: str           # sid
    user_id: str            # uid
    username: str           # un
    pp: float
    accuracy: float         # acc
    score: int              # sc
    max_combo: int          # cb
    grade: str              # gr
    mods: list[str]
    played_at: str          # at
    judgements: Optional[JudgementCounts]
    replay_id: Optional[str]

    @classmethod
    def from_dict(cls, data: dict) -> "LeaderboardScore":
        jc = data.get("jc")
        return cls(
            rank=data.get("rank", 0),
            score_id=data.get("sid", ""),
            user_id=data.get("uid", ""),
            username=data.get("un", ""),
            pp=data.get("pp", 0.0),
            accuracy=data.get("acc", 0.0),
            score=data.get("sc", 0),
            max_combo=data.get("cb", 0),
            grade=data.get("gr", ""),
            mods=data.get("mods", []),
            played_at=data.get("at", ""),
            judgements=JudgementCounts.from_dict(jc) if jc else None,
            replay_id=data.get("replayId"),
        )