import type { StoredArtifactRecord } from "../types/storage";
import { storedArtifactsToDomain } from "./storedArtifactAdapter";
import { recommendArtifacts, suggestBuilds } from "./scoring";
import type { AppSnapshot, Artifact, ArtifactSlot, Character, CharacterPreset, CharacterRole, ScanEvent } from "../types/domain";

const slotOrder: ArtifactSlot[] = ["flower", "plume", "sands", "goblet", "circlet"];

export function createLocalAccountSnapshot(records: StoredArtifactRecord[], basePresets: CharacterPreset[]): AppSnapshot | null {
  const artifacts = storedArtifactsToDomain(records);
  if (artifacts.length === 0) return null;

  const characters = inferCharacters(records, basePresets);
  const generatedPresets = createGeneratedPresets(characters, artifacts, basePresets);
  const presets = mergePresets(basePresets, generatedPresets);
  const recommendations = recommendArtifacts(artifacts, characters, presets);
  const builds = suggestBuilds(artifacts, characters, presets);
  const events: ScanEvent[] = [
    {
      id: "local-db-loaded",
      type: "complete",
      label: "Lokale Artifact-DB geladen",
      detail: `${artifacts.length} gespeicherte Artifacts, ${characters.filter((character) => character.owned).length} lokale Charaktere, ${builds.length} Build-Vorschlaege.`,
      confidence: 0.95,
    },
  ];

  return { artifacts, characters, recommendations, builds, scanEvents: events };
}

function inferCharacters(records: StoredArtifactRecord[], basePresets: CharacterPreset[]): Character[] {
  const equippedNames = [...new Set(records.map((record) => record.equipped.trim()).filter(isUsefulCharacterName))];
  const presetByName = new Map(basePresets.map((preset) => [simplify(preset.characterId), preset]));
  const characters: Character[] = [];

  for (const name of equippedNames) {
    const id = slug(name);
    const preset = presetByName.get(simplify(name)) ?? basePresets.find((entry) => simplify(entry.characterId).includes(simplify(name)));
    characters.push({
      id: preset?.characterId ?? id,
      name,
      owned: true,
      level: 90,
      constellation: 0,
      rolePreference: preset?.role ?? inferRoleFromRecords(records.filter((record) => record.equipped === name)),
      confidence: 0.82,
    });
  }

  for (const preset of basePresets) {
    if (characters.some((character) => character.id === preset.characterId)) continue;
    characters.push({
      id: preset.characterId,
      name: titleCase(preset.characterId.replaceAll("_", " ")),
      owned: false,
      level: 1,
      constellation: 0,
      rolePreference: preset.role,
      confidence: 0.5,
    });
  }

  return characters;
}

function createGeneratedPresets(characters: Character[], artifacts: Artifact[], basePresets: CharacterPreset[]): CharacterPreset[] {
  return characters
    .filter((character) => character.owned && !basePresets.some((preset) => preset.characterId === character.id))
    .map((character) => {
      const currentSets = mostCommonSetsForCharacter(character.name, artifacts);
      return {
        characterId: character.id,
        role: character.rolePreference,
        recommendedSets: currentSets.slice(0, 1),
        alternativeSets: currentSets.slice(1, 3),
        mainStats: inferMainStatsForRole(character.rolePreference),
        substatWeights: inferWeightsForRole(character.rolePreference),
        explanation: "Generated from locally scanned equipped artifacts. Review once curated character presets are added.",
      };
    });
}

function mostCommonSetsForCharacter(characterName: string, artifacts: Artifact[]) {
  const counts = new Map<string, number>();
  const equippedArtifacts = artifacts.filter((artifact) => artifact.equipped === characterName);
  const sourceArtifacts = equippedArtifacts.length ? equippedArtifacts : artifacts;
  for (const artifact of sourceArtifacts) {
    counts.set(artifact.setKey, (counts.get(artifact.setKey) ?? 0) + 1);
  }
  const ranked = [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([setKey]) => setKey);
  return ranked.length ? ranked : [`${slug(characterName)}_current_set`];
}

function mergePresets(basePresets: CharacterPreset[], generatedPresets: CharacterPreset[]) {
  const byId = new Map<string, CharacterPreset>();
  for (const preset of basePresets) byId.set(preset.characterId, preset);
  for (const preset of generatedPresets) if (!byId.has(preset.characterId)) byId.set(preset.characterId, preset);
  return [...byId.values()];
}

function inferRoleFromRecords(records: StoredArtifactRecord[]): CharacterRole {
  const text = records.flatMap((record) => [record.setName, record.mainStat, ...record.substats]).join(" ");
  if (/healing|maiden|clam/i.test(text)) return "healer";
  if (/viridescent|noblesse|scroll|cinder/i.test(text)) return "support";
  if (/elemental mastery|reaction|gilded|deepwood/i.test(text)) return "reaction";
  return "sub_dps";
}

function inferMainStatsForRole(role: CharacterRole): Partial<Record<ArtifactSlot, string[]>> {
  if (role === "support" || role === "reaction") {
    return {
      sands: ["Elemental Mastery", "Energy Recharge", "ATK%", "HP%"],
      goblet: ["Elemental Mastery", "Elemental DMG Bonus", "ATK%", "HP%"],
      circlet: ["Elemental Mastery", "CRIT Rate", "CRIT DMG", "Healing Bonus"],
    };
  }
  if (role === "healer") {
    return {
      sands: ["HP%", "Energy Recharge", "ATK%"],
      goblet: ["HP%", "Healing Bonus", "ATK%"],
      circlet: ["Healing Bonus", "HP%", "CRIT Rate"],
    };
  }
  return {
    sands: ["ATK%", "Energy Recharge", "Elemental Mastery", "HP%"],
    goblet: ["ATK%", "Physical DMG Bonus", "Hydro DMG Bonus", "Pyro DMG Bonus", "Electro DMG Bonus", "Cryo DMG Bonus", "Dendro DMG Bonus", "Anemo DMG Bonus", "Geo DMG Bonus"],
    circlet: ["CRIT Rate", "CRIT DMG", "ATK%", "Elemental Mastery"],
  };
}

function inferWeightsForRole(role: CharacterRole): Record<string, number> {
  if (role === "support") return { "Energy Recharge": 1.2, "CRIT Rate": 0.35, "CRIT DMG": 0.3, "ATK%": 0.25, "HP%": 0.25, "Elemental Mastery": 0.75 };
  if (role === "reaction") return { "Elemental Mastery": 1.25, "Energy Recharge": 0.8, "CRIT Rate": 0.5, "CRIT DMG": 0.45, "ATK%": 0.35 };
  if (role === "healer") return { "HP%": 1.1, "ATK%": 0.7, "Energy Recharge": 0.85, "CRIT Rate": 0.25, "CRIT DMG": 0.2 };
  return { "CRIT Rate": 1.15, "CRIT DMG": 1.1, "ATK%": 0.9, "Energy Recharge": 0.7, "Elemental Mastery": 0.45, "HP%": 0.3 };
}

function isUsefulCharacterName(value: string) {
  return Boolean(value && value !== "Not detected" && !/unknown|missing|detected/i.test(value));
}

function simplify(value: string) {
  return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
}

function slug(value: string) {
  return simplify(value).replace(/\s+/g, "_") || "unknown_character";
}

function titleCase(value: string) {
  return value.replace(/\b\w/g, (match) => match.toUpperCase());
}
