"""Mirrors upstream src/schemas/common.ts."""

from __future__ import annotations

from typing import Annotated, Literal

from pydantic import Field

from dnd5e_db.models.base import SRDModel


class APIReference(SRDModel):
    index: str
    name: str
    url: str
    note: str | None = None


class DifficultyClass(SRDModel):
    dc_type: APIReference
    dc_value: int | None = None
    success_type: Literal["none", "half", "other"]


class Damage(SRDModel):
    damage_type: APIReference
    damage_dice: str
    dc: DifficultyClass | None = None


class AreaOfEffect(SRDModel):
    size: int
    type: Literal["sphere", "cube", "cylinder", "line", "cone"]


class Choice(SRDModel):
    desc: str | None = None
    choose: int
    type: str | None = None
    from_: OptionSet = Field(alias="from")


class ReferenceOption(SRDModel):
    option_type: Literal["reference"]
    item: APIReference


class ChoiceOption(SRDModel):
    option_type: Literal["choice"]
    choice: Choice


class StringOption(SRDModel):
    option_type: Literal["string"]
    string: str


class AbilityBonusOption(SRDModel):
    option_type: Literal["ability_bonus"]
    ability_score: APIReference
    bonus: int


class ActionOption(SRDModel):
    option_type: Literal["action"]
    action_name: str
    count: int
    type: str
    desc: str | None = None


class BreathOption(SRDModel):
    option_type: Literal["breath"]
    name: str
    dc: DifficultyClass
    damage: list[Damage] | None = None


class CountedReferencePrerequisite(SRDModel):
    type: str
    proficiency: APIReference | None = None


class CountedReferenceOption(SRDModel):
    option_type: Literal["counted_reference"]
    count: int
    of: APIReference
    prerequisites: list[CountedReferencePrerequisite] | None = None


class DamageOption(SRDModel):
    option_type: Literal["damage"]
    damage_dice: str
    damage_type: APIReference
    notes: str | None = None


class IdealOption(SRDModel):
    option_type: Literal["ideal"]
    alignments: list[APIReference]
    desc: str


class MoneyOption(SRDModel):
    option_type: Literal["money"]
    count: int
    unit: str


class MultipleOption(SRDModel):
    option_type: Literal["multiple"]
    items: list[Option]
    desc: str | None = None


class ScorePrerequisiteOption(SRDModel):
    option_type: Literal["score_prerequisite"]
    ability_score: APIReference
    minimum_score: int


class SizeOption(SRDModel):
    option_type: Literal["size"]
    size: str


Option = Annotated[
    ReferenceOption
    | ChoiceOption
    | StringOption
    | AbilityBonusOption
    | ActionOption
    | BreathOption
    | CountedReferenceOption
    | DamageOption
    | IdealOption
    | MoneyOption
    | MultipleOption
    | ScorePrerequisiteOption
    | SizeOption,
    Field(discriminator="option_type"),
]


class EquipmentCategoryOptionSet(SRDModel):
    option_set_type: Literal["equipment_category"]
    equipment_category: APIReference


class ResourceListOptionSet(SRDModel):
    option_set_type: Literal["resource_list"]
    resource_list_url: str


class OptionsArrayOptionSet(SRDModel):
    option_set_type: Literal["options_array"]
    options: list[Option | str]


OptionSet = Annotated[
    EquipmentCategoryOptionSet | ResourceListOptionSet | OptionsArrayOptionSet,
    Field(discriminator="option_set_type"),
]

Choice.model_rebuild()
ChoiceOption.model_rebuild()
MultipleOption.model_rebuild()
OptionsArrayOptionSet.model_rebuild()
