import { AVAILABLE_BOSS_IDS, BOSS_DEFINITIONS } from "../bossCatalog";
import type { BossId } from "../types";

export type LootRarity = "common" | "uncommon" | "rare" | "epic" | "legendary";
export type DifficultySlug = "initiate" | "veteran" | "champion" | "mythic" | "ascendant";

export interface DifficultyDefinition {
  slug: DifficultySlug;
  name: string;
  itemLevel: number;
  rarity: LootRarity;
  glyph: string;
  coinPrefix: string;
  healthMultiplier: number;
  damageMultiplier: number;
}

export interface MaterialStack {
  id: string;
  name: string;
  quantity: number;
  rarity: LootRarity;
  itemLevel: number;
  glyph: string;
}

export interface BossCoinDrop {
  kind: "coin";
  id: string;
  bossId: BossId;
  difficultySlug: DifficultySlug;
  name: string;
  rarity: LootRarity;
  itemLevel: number;
  glyph: string;
  chanceLabel: string;
}

export interface BossPetDrop {
  kind: "pet";
  id: string;
  bossId: BossId;
  name: string;
  rarity: "legendary";
  glyph: string;
  dropRate: number;
  chanceLabel: string;
}

export interface BossDropTable {
  bossId: BossId;
  coins: Record<DifficultySlug, BossCoinDrop>;
  pet: BossPetDrop;
  entries: readonly (BossCoinDrop | BossPetDrop)[];
}

export interface CollectionLog {
  dropsFound: Record<string, number>;
  petsFound: Record<string, number>;
}

export interface BossRewardAward {
  bossId: BossId;
  coin: BossCoinDrop;
  quantity: number;
  quantityAfter: number;
  duplicate: boolean;
  pet: BossPetDrop | null;
  petQuantityAfter: number;
}

export const BOSS_PET_DROP_RATE = 1 / 500;

export const DIFFICULTIES: readonly DifficultyDefinition[] = [
  { slug: "initiate", name: "Initiate", itemLevel: 1, rarity: "common", glyph: "R", coinPrefix: "Raw", healthMultiplier: 1, damageMultiplier: 1 },
  { slug: "veteran", name: "Veteran", itemLevel: 10, rarity: "uncommon", glyph: "G", coinPrefix: "Green", healthMultiplier: 1.45, damageMultiplier: 1.25 },
  { slug: "champion", name: "Champion", itemLevel: 15, rarity: "rare", glyph: "B", coinPrefix: "Blue", healthMultiplier: 1.7, damageMultiplier: 1.45 },
  { slug: "mythic", name: "Mythic", itemLevel: 20, rarity: "epic", glyph: "P", coinPrefix: "Purple", healthMultiplier: 2.25, damageMultiplier: 1.85 },
  { slug: "ascendant", name: "Ascendant", itemLevel: 25, rarity: "legendary", glyph: "O", coinPrefix: "Orange", healthMultiplier: 2.8, damageMultiplier: 2.25 },
] as const;

export const DIFFICULTY_BY_SLUG = Object.fromEntries(
  DIFFICULTIES.map((difficulty) => [difficulty.slug, difficulty]),
) as Record<DifficultySlug, DifficultyDefinition>;

const DIFFICULTY_ID_PREFIX: Record<DifficultySlug, string> = {
  initiate: "raw",
  veteran: "green",
  champion: "blue",
  mythic: "purple",
  ascendant: "orange",
};

function createBossDropTable(bossId: BossId): BossDropTable {
  const boss = BOSS_DEFINITIONS[bossId];
  const coins = Object.fromEntries(DIFFICULTIES.map((difficulty) => [
    difficulty.slug,
    {
      kind: "coin" as const,
      id: `${DIFFICULTY_ID_PREFIX[difficulty.slug]}-${bossId}-coin`,
      bossId,
      difficultySlug: difficulty.slug,
      name: `${difficulty.coinPrefix} ${boss.name} Coin`,
      rarity: difficulty.rarity,
      itemLevel: difficulty.itemLevel,
      glyph: difficulty.glyph,
      chanceLabel: "Guaranteed 1-3",
    },
  ])) as Record<DifficultySlug, BossCoinDrop>;
  const pet: BossPetDrop = {
      kind: "pet",
      id: `${bossId}-pet`,
      bossId,
      name: `${boss.name} Pet`,
      rarity: "legendary",
      glyph: boss.icon,
      dropRate: BOSS_PET_DROP_RATE,
      chanceLabel: "1 in 500",
  };
  return {
    bossId,
    coins,
    pet,
    entries: [...DIFFICULTIES.map((difficulty) => coins[difficulty.slug]), pet],
  };
}

export const BOSS_DROP_TABLES = Object.fromEntries(
  AVAILABLE_BOSS_IDS.map((bossId) => [bossId, createBossDropTable(bossId)]),
) as Record<BossId, BossDropTable>;

export function bossDropTable(bossId: BossId): BossDropTable {
  return BOSS_DROP_TABLES[bossId];
}

export function bossCoinDrop(bossId: BossId, difficultySlug: DifficultySlug): BossCoinDrop {
  return BOSS_DROP_TABLES[bossId].coins[difficultySlug];
}

export function coinDropQuantity(random: () => number = Math.random): number {
  const roll = random();
  if (roll < 0.15) return 3;
  if (roll < 0.5) return 2;
  return 1;
}

export function rollBossReward(
  bossId: BossId,
  difficultySlug: DifficultySlug,
  inventory: readonly MaterialStack[],
  collectionLog: CollectionLog,
  random: () => number = Math.random,
): { award: BossRewardAward; inventory: MaterialStack[]; collectionLog: CollectionLog } {
  const table = bossDropTable(bossId);
  const coin = table.coins[difficultySlug];
  const quantity = coinDropQuantity(random);
  const existing = inventory.find((item) => item.id === coin.id);
  const inventoryAfter = existing
    ? inventory.map((item) => item.id === coin.id ? { ...item, quantity: item.quantity + quantity } : { ...item })
    : [...inventory.map((item) => ({ ...item })), { id: coin.id, name: coin.name, quantity, rarity: coin.rarity, itemLevel: coin.itemLevel, glyph: coin.glyph }];
  const petAwarded = random() < table.pet.dropRate;
  const petQuantityAfter = (collectionLog.petsFound[table.pet.id] ?? 0) + Number(petAwarded);
  return {
    award: {
      bossId,
      coin,
      quantity,
      quantityAfter: (existing?.quantity ?? 0) + quantity,
      duplicate: Boolean(existing),
      pet: petAwarded ? table.pet : null,
      petQuantityAfter,
    },
    inventory: inventoryAfter,
    collectionLog: {
      dropsFound: {
        ...collectionLog.dropsFound,
        [coin.id]: (collectionLog.dropsFound[coin.id] ?? 0) + quantity,
      },
      petsFound: petAwarded
        ? { ...collectionLog.petsFound, [table.pet.id]: petQuantityAfter }
        : { ...collectionLog.petsFound },
    },
  };
}

export function normalizeDifficultySlug(value: unknown): DifficultySlug {
  return typeof value === "string" && value in DIFFICULTY_BY_SLUG
    ? value as DifficultySlug
    : "initiate";
}

export function createEmptyCollectionLog(): CollectionLog {
  return { dropsFound: {}, petsFound: {} };
}
