import type { GoodExportArtifact } from "../types/global";
import type { StoredArtifactRecord } from "../types/storage";
import { knownSets, mainStatValueReferences, pieceToSet, pieceToSlot } from "./genshinData";
import { simplifyForMatch } from "./fuzzyMatch";
import { inferRarity } from "./substatRolls";

// GOOD (Genshin Open Object Description) interop for scanned artifacts, so the
// local store can round-trip with GOOD-compatible tools (ADR-003). Export is
// lossless for the fields GOOD carries; import is
// best-effort because GOOD does not store piece names or main-stat values.

export interface GoodImportArtifact {
  setKey: string;
  slotKey: string;
  rarity?: number;
  level?: number;
  mainStatKey: string;
  substats?: Array<{ key: string; value: number }>;
  location?: string;
  lock?: boolean;
}

export interface GoodImportDatabase {
  format?: string;
  version?: number;
  source?: string;
  artifacts?: GoodImportArtifact[];
}

const SLOT_TO_GOOD: Record<string, string> = {
  "Flower of Life": "flower",
  "Plume of Death": "plume",
  "Sands of Eon": "sands",
  "Goblet of Eonothem": "goblet",
  "Circlet of Logos": "circlet",
};

const GOOD_TO_SLOT: Record<string, string> = Object.fromEntries(
  Object.entries(SLOT_TO_GOOD).map(([display, key]) => [key, display]),
);

// display name (as used across the app, including the HP%/ATK%/DEF% variants) ->
// GOOD stat key + whether it is a percent stat.
interface StatEntry {
  display: string;
  key: string;
  percent: boolean;
}

const STAT_ENTRIES: StatEntry[] = [
  { display: "HP", key: "hp", percent: false },
  { display: "HP%", key: "hp_", percent: true },
  { display: "ATK", key: "atk", percent: false },
  { display: "ATK%", key: "atk_", percent: true },
  { display: "DEF", key: "def", percent: false },
  { display: "DEF%", key: "def_", percent: true },
  { display: "Elemental Mastery", key: "eleMas", percent: false },
  { display: "Energy Recharge", key: "enerRech_", percent: true },
  { display: "CRIT Rate", key: "critRate_", percent: true },
  { display: "CRIT DMG", key: "critDMG_", percent: true },
  { display: "Healing Bonus", key: "heal_", percent: true },
  { display: "Physical DMG Bonus", key: "physical_dmg_", percent: true },
  { display: "Pyro DMG Bonus", key: "pyro_dmg_", percent: true },
  { display: "Hydro DMG Bonus", key: "hydro_dmg_", percent: true },
  { display: "Electro DMG Bonus", key: "electro_dmg_", percent: true },
  { display: "Cryo DMG Bonus", key: "cryo_dmg_", percent: true },
  { display: "Anemo DMG Bonus", key: "anemo_dmg_", percent: true },
  { display: "Geo DMG Bonus", key: "geo_dmg_", percent: true },
  { display: "Dendro DMG Bonus", key: "dendro_dmg_", percent: true },
];

const DISPLAY_TO_STAT = new Map(STAT_ENTRIES.map((entry) => [entry.display, entry]));
const KEY_TO_STAT = new Map(STAT_ENTRIES.map((entry) => [entry.key, entry]));

export function statDisplayToGoodKey(display: string): string {
  return DISPLAY_TO_STAT.get(display)?.key ?? "";
}

export function goodKeyToStatDisplay(key: string): string {
  return KEY_TO_STAT.get(key)?.display ?? "";
}

export function setNameToKey(name: string): string {
  // GOOD removes apostrophes without re-capitalizing ("Gladiator's" ->
  // "Gladiators"), then PascalCases the remaining whitespace/hyphen words.
  return name
    .replace(/['’]/g, "")
    .split(/[\s-]+/)
    .map((word) => word.replace(/[^A-Za-z0-9]/g, ""))
    .filter(Boolean)
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
    .join("");
}

const SET_KEY_TO_NAME = new Map(knownSets.map((name) => [setNameToKey(name), name]));

export function setKeyToName(key: string): string {
  const direct = SET_KEY_TO_NAME.get(key);
  if (direct) return direct;
  const simplifiedKey = simplifyForMatch(key);
  const match = knownSets.find((name) => simplifyForMatch(setNameToKey(name)) === simplifiedKey);
  return match ?? key;
}

// "CRIT DMG+13.2%" / "ATK+19" -> GOOD { key, value }.
export function substatStringToGood(entry: string): { key: string; value: number } | null {
  const plusIndex = entry.indexOf("+");
  if (plusIndex <= 0) return null;
  const display = entry.slice(0, plusIndex).trim();
  const key = statDisplayToGoodKey(display);
  if (!key) return null;
  const value = Number.parseFloat(entry.slice(plusIndex + 1).replace(/[%,\s]/g, ""));
  if (!Number.isFinite(value)) return null;
  return { key, value };
}

export function goodSubstatToString(substat: { key: string; value: number }): string {
  const entry = KEY_TO_STAT.get(substat.key);
  if (!entry) return "";
  return entry.percent ? `${entry.display}+${substat.value}%` : `${entry.display}+${substat.value}`;
}

export function storedArtifactToGood(record: StoredArtifactRecord): GoodExportArtifact {
  const substats = record.substats
    .map((entry) => substatStringToGood(entry))
    .filter((entry): entry is { key: string; value: number } => entry !== null);

  return {
    setKey: setNameToKey(record.setName),
    slotKey: SLOT_TO_GOOD[record.slot] ?? "",
    rarity: inferRarity(record.level ?? 0, record.substats),
    level: record.level ?? 0,
    mainStatKey: statDisplayToGoodKey(record.mainStat),
    substats,
    lock: Boolean((record as { locked?: boolean }).locked),
  };
}

export function storedArtifactsToGood(records: readonly StoredArtifactRecord[], source = "Genshin Artifact Assistant") {
  return {
    format: "GOOD" as const,
    version: 2,
    source,
    artifacts: records.map(storedArtifactToGood),
  };
}

function reversePieceLookup(setName: string, slotDisplay: string): string {
  for (const [piece, set] of pieceToSet.entries()) {
    if (set === setName && pieceToSlot.get(piece) === slotDisplay) return piece;
  }
  return "";
}

function computeMainValue(slotDisplay: string, mainStatDisplay: string, level: number): string {
  const references = mainStatValueReferences[slotDisplay];
  const reference = Array.isArray(references)
    ? (references as Array<{ stat: string; base: number; max: number }>).find((entry) => entry.stat === mainStatDisplay)
    : undefined;
  if (!reference) return "";
  const clamped = Math.max(0, Math.min(20, level));
  const value = reference.base + (reference.max - reference.base) * (clamped / 20);
  const isPercent = DISPLAY_TO_STAT.get(mainStatDisplay)?.percent ?? false;
  return isPercent ? `${(Math.round(value * 10) / 10).toFixed(1)}%` : Math.round(value).toLocaleString("en-US");
}

export function goodToStoredArtifact(good: GoodImportArtifact, index = 0): StoredArtifactRecord | null {
  const slot = GOOD_TO_SLOT[good.slotKey];
  const mainStat = goodKeyToStatDisplay(good.mainStatKey);
  if (!slot || !mainStat) return null;

  const setName = setKeyToName(good.setKey);
  const level = typeof good.level === "number" ? good.level : 0;
  const substats = (good.substats ?? [])
    .map((substat) => goodSubstatToString(substat))
    .filter(Boolean);
  const name = reversePieceLookup(setName, slot) || setName;

  return {
    id: `good-${good.setKey}-${good.slotKey}-${index}`,
    name,
    slot,
    level,
    setName,
    mainStat,
    mainValue: computeMainValue(slot, mainStat, level),
    substats,
    equipped: good.location || "Not detected",
    confidence: 100,
    needsReview: false,
    source: "good-import",
  };
}

export function goodDatabaseToStoredArtifacts(database: GoodImportDatabase | null | undefined): StoredArtifactRecord[] {
  const records: StoredArtifactRecord[] = [];
  (database?.artifacts ?? []).forEach((artifact, index) => {
    const record = goodToStoredArtifact(artifact, index);
    if (record) records.push(record);
  });
  return records;
}
