export type MemberId = "aelia" | "brann" | "nia" | "orin" | "vale";
export type AbilityId = "mend" | "renew" | "shield" | "purify" | "radiance" | "barrier";
export type BossId =
  | "bulldrome"
  | "sandglass-scorpion"
  | "cragclaw-crab"
  | "mournveil-ghost"
  | "crownshard-golem"
  | "crystal-bat-matriarch"
  | "stormwool-alpaca"
  | "cluckhorn-colossus"
  | "ashwing-demon"
  | "riftclaw-demon"
  | "tempestscale-dragon"
  | "emberfox"
  | "mirelord-frog"
  | "stonebreaker-giant"
  | "glub-sovereign"
  | "scrapking-goblin"
  | "warcaller-orc"
  | "tuskmaw-orc"
  | "broodfang-spider"
  | "silkfang-spider"
  | "thorncrown-stag"
  | "sky-totem"
  | "razorcrest-raptor"
  | "bristlequake-boar"
  | "moonfang-wolf"
  | "frostmaw-yeti"
  | "rimeclaw-yeti"
  | "gravehorn-triceratops";
export type BossMechanicId =
  | "basic-melee"
  | "bull-charge"
  | "crushing-pounce"
  | "cinder-nova"
  | "ember-brand"
  | "binding-web"
  | "venom-purge"
  | "storm-breath"
  | "stormfall"
  | "elemental-beam"
  | "guardian-cross"
  | "destruction-rush"
  | "ruin-quake"
  | "destruction-pulse"
  | "ricochet-rush"
  | "meteor-slam"
  | "burrow-rush"
  | "hourglass-eruption"
  | "sidewinder-rush"
  | "crushing-tide"
  | "vine-scissors"
  | "haunting-rifts"
  | "tri-burst"
  | "ultimate-skyfall"
  | "meteor-spread"
  | "hollow-collapse"
  | "aetheric-soak"
  | "prism-beam"
  | "memory-sequence"
  | "soul-siphon";
export type BossAnimationCue = "idle" | "move" | "attack" | "special";
export type GamePhase = "briefing" | "combat" | "intermission" | "victory" | "defeat";
export type RunMode = "encounter" | "roguelike" | "rogue-trials";
export type RunBuffId =
  | "mend-echo"
  | "mend-efficiency"
  | "mend-cast-speed"
  | "renew-spread"
  | "renew-duration"
  | "renew-potency"
  | "shield-echo"
  | "shield-potency"
  | "shield-guard"
  | "purify-renew"
  | "purify-shield"
  | "purify-chain"
  | "radiance-cooldown"
  | "radiance-renew"
  | "radiance-shield"
  | "barrier-cooldown"
  | "barrier-duration"
  | "barrier-regen";
export type RunBuffRanks = Partial<Record<RunBuffId, number>>;
export type BottomTab = "combat" | "map" | "pack";
export type PulseKind = AbilityId | "boss" | "debuff" | "charge" | "pounce" | "tether" | "venom" | "breath" | "skyfall" | "slash";
export type BossMotionMode =
  | "holding"
  | "telegraph"
  | "charging"
  | "stacking"
  | "pouncing"
  | "tethering"
  | "venom_cast"
  | "breath_telegraph"
  | "breath_sweeping"
  | "skyfall"
  | "mantis_line_telegraph"
  | "mantis_cross_telegraph"
  | "cinderback_slam"
  | "sandglass_hourglass"
  | "golem_shockwave"
  | "golem_crownfall";
export type WorldPosition = [number, number];

export type CircleHazardKind =
  | "venom_pool"
  | "skyfall"
  | "quake"
  | "lava_pool"
  | "stinger_eruption"
  | "hourglass"
  | "tidal_burst"
  | "soul_rift"
  | "crownfall"
  | "royal_shockwave";

export type PoolTelegraphKind = "spread" | "donut" | "soak" | "beam" | "memory" | "soul-siphon";

export type MemorySymbolId = "triangle" | "cross" | "circle" | "square";

export interface MemoryTile {
  symbol: MemorySymbolId;
  center: WorldPosition;
}

/**
 * Short-lived, encounter-agnostic boss mechanic. Individual boss scripts keep
 * ownership of their signature moves; this shape lets an encounter add a
 * balanced mechanic from the shared pool without adding another boss mode.
 */
export interface PoolTelegraph {
  id: string;
  kind: PoolTelegraphKind;
  name: string;
  center: WorldPosition;
  radius: number;
  innerRadius?: number;
  start?: WorldPosition;
  end?: WorldPosition;
  width?: number;
  activatesAt: number;
  expiresAt: number;
  damage: number;
  totalDamage?: number;
  minimumParticipants?: number;
  targetId?: MemberId;
  /** Healer-only Simon Says state. Present only for the Memory Sequence pool mechanic. */
  sequence?: MemorySymbolId[];
  tiles?: MemoryTile[];
  inputStartsAt?: number;
  inputIndex?: number;
  lastHealerTileId?: MemorySymbolId;
  soulSiphon?: SoulSiphonState;
  resolved: boolean;
  hitIds: MemberId[];
}

export interface CircleHazard {
  id: string;
  kind: CircleHazardKind;
  center: WorldPosition;
  innerRadius?: number;
  radius: number;
  activatesAt: number;
  expiresAt: number;
  damage: number;
  tickInterval?: number;
  nextDamageAt: Partial<Record<MemberId, number>>;
  resolved: boolean;
  hitIds: MemberId[];
}

export interface SlashLane {
  id: string;
  start: WorldPosition;
  end: WorldPosition;
  width: number;
  damage: number;
}

/**
 * Healer-only movement objective. The encounter owns the rules; renderers use
 * this compact state to show the pursuing shade and its cleansing destination.
 */
export interface SoulSiphonState {
  targetId: "aelia";
  ghostPosition: WorldPosition;
  wardPosition: WorldPosition;
  wardRadius: number;
  nextDamageAt: number;
  tickCount: number;
}

export interface Debuff {
  id: string;
  name: string;
  expiresAt: number;
  nextTickAt: number;
  tickDamage: number;
  sourceBossId?: BossId;
}

export interface PartyMember {
  id: MemberId;
  name: string;
  className: string;
  role: "Healer" | "Tank" | "Damage";
  color: string;
  maxHp: number;
  hp: number;
  absorb: number;
  renewExpiresAt: number;
  renewNextTickAt: number;
  knockedUntil: number;
  debuffs: Debuff[];
}

export interface BossState {
  id: BossId;
  name: string;
  maxHp: number;
  hp: number;
  nextMeleeAt: number;
  /** Simulation time when health first reached zero. Used for delayed endless replacement. */
  defeatedAt?: number;
}

export interface BossMotionState {
  bossId: BossId;
  activeMechanicId: BossMechanicId | null;
  formationOffsetX: number;
  mode: BossMotionMode;
  position: WorldPosition;
  chargeStart: WorldPosition;
  chargeEnd: WorldPosition;
  chargeTargetId: MemberId;
  chargeHitIds: MemberId[];
  phaseEndsAt: number;
  chargeCount: number;
  pounceTargetId: MemberId;
  pounceCenter: WorldPosition;
  nextMechanicAt: number;
  mechanicCount: number;
  phaseStartedAt: number;
  mechanicHitIds: MemberId[];
  mechanicNextDamageAt: Partial<Record<MemberId, number>>;
  tetherIds: MemberId[];
  tetherBreakDistance: number;
  breathAngle: number;
  breathStartAngle: number;
  breathEndAngle: number;
  hazards: CircleHazard[];
  slashLanes: SlashLane[];
  poolMechanicCount: number;
  poolTelegraphs: PoolTelegraph[];
}

export interface AbilityDefinition {
  id: AbilityId;
  name: string;
  shortName: string;
  key: string;
  gamepad: string;
  cooldown: number;
  castTime?: number;
  mana: number;
  icon: string;
  description: string;
  targeting: "enemy" | "ally" | "party";
  color: string;
}

export interface ActiveCast {
  abilityId: "mend";
  targetId: MemberId;
  startedAt: number;
  completesAt: number;
}

export interface BarrierState {
  center: WorldPosition;
  expiresAt: number;
  nextHealAt: number;
}

export interface ScenePulse {
  id: number;
  kind: PulseKind;
  targetId?: MemberId;
}

export interface InventoryItem {
  id: string;
  name: string;
  slot: string;
  rarity: "Common" | "Uncommon" | "Rare";
  icon: string;
  stats: string[];
  effect: string;
  equipped: boolean;
}

export type HealerClassId = "priest" | "druid" | "shaman";

export interface HealerClassDefinition {
  id: HealerClassId;
  name: string;
  specialization: string;
  icon: string;
  color: string;
  resourceName: string;
  description: string;
  abilities: Record<AbilityId, AbilityDefinition>;
}
