import gameData from "../data/genshinGameData.json" with { type: "json" };
import { simplifyForMatch } from "./fuzzyMatch.js";

type ArtifactPiece = {
  name: string;
  setName: string;
  slot: string;
  relicType: string;
};

type Character = {
  name: string;
};

type GenshinGameDataContract = typeof gameData & {
  artifactPieces?: ArtifactPiece[];
  stats?: {
    main?: string[];
    mainBySlot?: Record<string, string[]>;
    sub?: string[];
  };
  aliases?: {
    stats?: Record<string, string>;
    textReplacements?: Record<string, string>;
    slotAliases?: Record<string, string>;
    setAliases?: Record<string, string>;
    pieceAliases?: Record<string, string>;
    characterAliases?: Record<string, string>;
  };
  mainStatsBySlot?: Record<string, string[]>;
  mainStatValueReferences?: Record<string, Array<{ stat: string; base: number; max: number }>>;
  characters?: Character[];
};

export const genshinGameData = gameData as GenshinGameDataContract;

export const slotNames = genshinGameData.slots;
export const statAliases = genshinGameData.aliases?.stats ?? {};
export const textReplacements = genshinGameData.aliases?.textReplacements ?? {};
export const slotAliases = genshinGameData.aliases?.slotAliases ?? {};
export const setAliases = genshinGameData.aliases?.setAliases ?? {};
export const pieceAliases = genshinGameData.aliases?.pieceAliases ?? {};
export const characterAliases = genshinGameData.aliases?.characterAliases ?? {};
export const knownSets = genshinGameData.artifactSets.map((set) => set.name);
export const knownCharacters = (genshinGameData.characters ?? []).map((character) => character.name);
export const sourceVersion = genshinGameData.sourceVersion ?? "unknown";

export const fixedMainStatBySlot: Record<string, string> = {
  "Flower of Life": "HP",
  "Plume of Death": "ATK",
};

const bundledMainStats = genshinGameData.stats?.main ?? genshinGameData.mainStats;
const bundledSubstats = genshinGameData.stats?.sub ?? genshinGameData.substats;

export const mainStatsBySlot: Record<string, string[]> = genshinGameData.stats?.mainBySlot ?? genshinGameData.mainStatsBySlot ?? {
  "Flower of Life": ["HP"],
  "Plume of Death": ["ATK"],
  "Sands of Eon": ["HP%", "ATK%", "DEF%", "Energy Recharge", "Elemental Mastery"],
  "Goblet of Eonothem": [
    "HP%",
    "ATK%",
    "DEF%",
    "Elemental Mastery",
    "Hydro DMG Bonus",
    "Pyro DMG Bonus",
    "Electro DMG Bonus",
    "Cryo DMG Bonus",
    "Dendro DMG Bonus",
    "Anemo DMG Bonus",
    "Geo DMG Bonus",
    "Physical DMG Bonus",
  ],
  "Circlet of Logos": ["HP%", "ATK%", "DEF%", "Elemental Mastery", "CRIT Rate", "CRIT DMG", "Healing Bonus"],
};

const fallbackArtifactPieces = genshinGameData.artifactSets.flatMap((artifactSet) =>
  artifactSet.pieces.map((piece) => ({
    name: piece.name,
    setName: artifactSet.name,
    slot: slotFromRelicType(piece.relicType),
    relicType: piece.relicType,
  })),
);

export const artifactPieces: ArtifactPiece[] = (genshinGameData.artifactPieces ?? fallbackArtifactPieces)
  .filter((piece) => piece.name && piece.setName && piece.slot);

export const pieceToSet = new Map(artifactPieces.map((piece) => [piece.name, piece.setName]));
export const pieceToSlot = new Map(artifactPieces.map((piece) => [piece.name, piece.slot]));
export const knownPieceNames = artifactPieces.map((piece) => piece.name);

export const globalMainStats = unique([
  ...bundledMainStats,
  ...Object.keys(statAliases),
]);

export const globalSubstats = unique([
  ...bundledSubstats,
  ...Object.keys(statAliases),
]);

export const mainStatValueReferences = genshinGameData.mainStatValueReferences ?? {};

export function allowedMainStatsForSlot(slot: string) {
  return mainStatsBySlot[slot] ?? globalMainStats;
}

export function canonicalStatName(raw: string) {
  return statAliases[raw] ?? raw;
}

export function normalizeSlotAlias(raw: string) {
  const simplified = simplifyForMatch(raw);
  const aliasMatch = Object.entries(slotAliases).find(([alias]) => simplifyForMatch(alias) === simplified);
  if (aliasMatch) return aliasMatch[1];
  const direct = slotNames.find((slot) => simplifyForMatch(slot) === simplified);
  return direct ?? "";
}

export function normalizeSetAlias(raw: string) {
  const simplified = simplifyForMatch(raw);
  const aliasMatch = Object.entries(setAliases).find(([alias]) => simplifyForMatch(alias) === simplified);
  if (aliasMatch) return aliasMatch[1];
  const direct = knownSets.find((set) => simplifyForMatch(set) === simplified);
  return direct ?? "";
}

export function normalizePieceAlias(raw: string) {
  const simplified = simplifyForMatch(raw);
  const aliasMatch = Object.entries(pieceAliases).find(([alias]) => simplifyForMatch(alias) === simplified);
  if (aliasMatch) return aliasMatch[1];
  const direct = knownPieceNames.find((piece) => simplifyForMatch(piece) === simplified);
  return direct ?? "";
}

export function normalizeCharacterAlias(raw: string) {
  const simplified = simplifyForMatch(raw);
  const aliasMatch = Object.entries(characterAliases).find(([alias]) => simplifyForMatch(alias) === simplified);
  if (aliasMatch) return aliasMatch[1];
  const direct = knownCharacters.find((character) => simplifyForMatch(character) === simplified);
  return direct ?? "";
}

function unique(values: string[]) {
  return [...new Set(values)];
}

function slotFromRelicType(relicType: string) {
  switch (relicType) {
    case "EQUIP_BRACER":
      return "Flower of Life";
    case "EQUIP_NECKLACE":
      return "Plume of Death";
    case "EQUIP_SHOES":
      return "Sands of Eon";
    case "EQUIP_RING":
      return "Goblet of Eonothem";
    case "EQUIP_DRESS":
      return "Circlet of Logos";
    default:
      return "";
  }
}
