import type { AbilityLoadout, BossId, HealerAbilityId } from "../types";

export type { AbilityLoadout } from "../types";

export const RPG_ROGUELIKE_MODE_ID = "rpg-roguelike" as const;
export const PARTY_DRAFT_WAVE_COUNT = 3;
export const PARTY_OFFERS_PER_WAVE = 5;
export const PARTY_RECRUITS_PER_WAVE = 3;
export const MAX_ACTIVE_ROSTER = 4;
export const SPELL_DRAFT_WAVE_COUNT = 3;
export const SPELL_OFFERS_PER_WAVE = 3;
export const SPELL_PICKS_PER_WAVE = 2;
export const MAX_EQUIPPED_SPELLS = 6;
export const ACT_COUNT = 3;
export const BOSSES_PER_ACT = 3;
export const ACT_BOSS_COUNT = ACT_COUNT * BOSSES_PER_ACT;
export const TOTAL_BOSS_COUNT = ACT_BOSS_COUNT + 1;
export const MAX_SPELL_RANK = 5;
export const MAX_RUN_GEAR_ENHANCEMENT = 5;

export type RpgRunPhase =
  | "party-draft"
  | "spell-draft"
  | "challenge-briefing"
  | "challenge-active"
  | "boss-briefing"
  | "boss-combat"
  | "boss-cleared"
  | "reward"
  | "shop"
  | "victory"
  | "defeat";

export interface RandomState {
  readonly seed: number;
  readonly state: number;
  readonly draws: number;
}

export type PartyRarity = "white" | "green" | "blue" | "purple" | "gold";
export type PartyRole = "Tank" | "Damage";
export type PartyClassId = "knight" | "ranger" | "mage" | "rogue" | "warrior" | "warlock" | "monk";
export type PartyArchetypeId =
  | "knight-tank"
  | "ranger-damage"
  | "mage-damage"
  | "rogue-damage"
  | "warrior-tank"
  | "warrior-damage"
  | "warlock-damage"
  | "monk-tank"
  | "monk-damage";
export type PartyTraitId =
  | "steadfast"
  | "battle-hardened"
  | "guardian-instinct"
  | "royal-aegis"
  | "sure-footed"
  | "eagle-eye"
  | "rapid-volley"
  | "perfect-shot"
  | "arcane-focus"
  | "spell-echo"
  | "volatile-power"
  | "astral-mastery"
  | "light-footed"
  | "exploit-opening"
  | "blade-dance"
  | "shadow-master"
  | "iron-blood"
  | "whirlwind"
  | "war-cry"
  | "unstoppable"
  | "soul-drain"
  | "doom-mark"
  | "dark-pact"
  | "soul-tyrant"
  | "centered"
  | "counterstrike"
  | "flow-state"
  | "perfect-form";

export interface PartyCombatStats {
  readonly maxHp: number;
  readonly singleTarget: number;
  readonly areaDamage: number;
  readonly defense: number;
  readonly moveSpeed: number;
}

export interface PartyDraftCandidate {
  readonly candidateId: string;
  readonly name: string;
  readonly archetypeId: PartyArchetypeId;
  readonly classId: PartyClassId;
  readonly className: string;
  readonly role: PartyRole;
  readonly rarity: PartyRarity;
  readonly stats: PartyCombatStats;
  readonly traitIds: PartyTraitId[];
  readonly color: string;
}

export interface PartyRosterMember extends PartyDraftCandidate {
  readonly instanceId: string;
  readonly hp: number;
}

export type AllyCombatSlotId = "brann" | "nia" | "orin" | "vale";
export type CombatPartyAssignment = Record<AllyCombatSlotId, PartyRosterMember | null>;

export interface PartyDraftState {
  readonly waveIndex: number;
  readonly offers: PartyDraftCandidate[];
  readonly recruitedThisWaveIds: string[];
}

export interface SpellDraftState {
  readonly waveIndex: number;
  readonly offers: HealerAbilityId[];
  readonly pickedThisWaveIds: HealerAbilityId[];
  readonly seenOfferIds: HealerAbilityId[];
}

export type ChallengeId = "blockbreaker" | "hockey" | "aether-assault";
export type ChallengeMetric = "bricksBroken" | "bossKills" | "kills";

export interface ChallengeMetrics {
  readonly bricksBroken: number;
  readonly bossKills: number;
  readonly kills: number;
}

export interface ChallengeObjective {
  readonly challengeId: ChallengeId;
  readonly name: string;
  readonly metric: ChallengeMetric;
  readonly target: number;
  readonly repeatIndex: number;
  readonly rewardCurrency: number;
  readonly chestQualityBonus: number;
}

export interface ChallengeRunState {
  readonly objective: ChallengeObjective;
  readonly metrics: ChallengeMetrics;
}

export interface ChallengeResult {
  readonly objective: ChallengeObjective;
  readonly metrics: ChallengeMetrics;
  readonly succeeded: boolean;
}

export type RunGearSlotId = "weapon" | "armor" | "trinket";
export type RunGearOwnerId = "player" | string;
export type RunGearStatId = "damage" | "maxHealth" | "haste";

export interface RunGearItem {
  readonly id: string;
  readonly ownerId: RunGearOwnerId;
  readonly slotId: RunGearSlotId;
  readonly enhancement: 0 | 1 | 2 | 3 | 4 | 5;
  readonly name: string;
  readonly statId: RunGearStatId;
  readonly statValue: number;
  readonly sellPrice: number;
}

export type RunEquipment = Record<string, Partial<Record<RunGearSlotId, RunGearItem>>>;

export type RewardChoice =
  | {
      readonly id: string;
      readonly kind: "spell-rank";
      readonly spellId: HealerAbilityId;
      readonly nextRank: number;
      readonly label: string;
    }
  | {
      readonly id: string;
      readonly kind: "member-rarity";
      readonly memberId: string;
      readonly nextRarity: PartyRarity;
      readonly label: string;
    }
  | {
      readonly id: string;
      readonly kind: "run-gear";
      readonly item: RunGearItem;
      readonly label: string;
    }
  | {
      readonly id: string;
      readonly kind: "currency";
      readonly amount: number;
      readonly label: string;
    };

export interface RewardChest {
  readonly id: string;
  readonly quality: number;
  readonly choices: RewardChoice[];
}

export interface ShopOffer {
  readonly id: string;
  readonly item: RunGearItem;
  readonly price: number;
  readonly sold: boolean;
}

export interface RunShopState {
  readonly act: number;
  readonly offers: ShopOffer[];
  readonly restCost: number;
  readonly reviveCost: number;
}

export interface PartyVitalUpdate {
  readonly instanceId: string;
  readonly hp: number;
}

export interface RpgRoguelikeRunState {
  readonly version: 1;
  readonly seed: number;
  readonly random: RandomState;
  readonly phase: RpgRunPhase;
  readonly partyDraft: PartyDraftState | null;
  readonly spellDraft: SpellDraftState | null;
  readonly roster: PartyRosterMember[];
  readonly selectedSpellIds: HealerAbilityId[];
  readonly abilityLoadout: AbilityLoadout;
  readonly spellRanks: Partial<Record<HealerAbilityId, number>>;
  /** Gear-independent healer vitality, normalized against a 100 HP run base. */
  readonly playerHp: number;
  readonly bossRoute: BossId[];
  readonly bossIndex: number;
  readonly bossesDefeated: number;
  readonly challengeCounts: Record<ChallengeId, number>;
  readonly currentChallenge: ChallengeRunState | null;
  readonly lastChallengeResult: ChallengeResult | null;
  readonly nextChestQualityBonus: number;
  readonly pendingReward: RewardChest | null;
  readonly equipment: RunEquipment;
  readonly bag: RunGearItem[];
  readonly currency: number;
  readonly shop: RunShopState | null;
}

export interface RpgRoguelikeRunConfig {
  readonly seed: number | string;
  readonly bossPool?: readonly BossId[];
  readonly startingCurrency?: number;
}

export type RpgRoguelikeAction =
  | { readonly type: "party-recruit"; readonly candidateId: string }
  | { readonly type: "party-remove"; readonly memberId: string }
  | { readonly type: "party-next-wave" }
  | { readonly type: "spell-pick"; readonly spellId: HealerAbilityId }
  | { readonly type: "spell-remove"; readonly spellId: HealerAbilityId }
  | { readonly type: "spell-next-wave" }
  | { readonly type: "challenge-start" }
  | { readonly type: "challenge-progress"; readonly metrics: Partial<ChallengeMetrics> }
  | { readonly type: "challenge-complete"; readonly metrics?: Partial<ChallengeMetrics>; readonly forcedFailure?: boolean }
  | { readonly type: "boss-start" }
  | { readonly type: "party-vitals"; readonly vitals: readonly PartyVitalUpdate[]; readonly playerHp?: number }
  | { readonly type: "boss-won"; readonly vitals?: readonly PartyVitalUpdate[]; readonly playerHp?: number }
  | { readonly type: "boss-lost"; readonly vitals?: readonly PartyVitalUpdate[]; readonly playerHp?: number }
  | { readonly type: "reward-open" }
  | { readonly type: "reward-choose"; readonly choiceId: string }
  | { readonly type: "shop-buy"; readonly offerId: string }
  | { readonly type: "shop-sell"; readonly itemId: string }
  | { readonly type: "shop-rest" }
  | { readonly type: "shop-revive"; readonly memberId: string }
  | { readonly type: "shop-leave" };
