import { asIwt2HealerId, type Iwt2HealerId } from '../content/healerAbilities'

export type Iwt2InventoryItem = {
  id: string
  name: string
  quantity: number
  rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary'
}

export type Iwt2ArmorPaletteId = 'guild_green' | 'sun_gold' | 'ember_red' | 'moon_blue'

export type Iwt2CollectionLog = {
  bossKills: Record<string, number>
  dropsFound: Record<string, number>
}

export type Iwt2Character = {
  name: string
  level: number
  experience: number
  healerStyle: Iwt2HealerId
  armorPalette: Iwt2ArmorPaletteId
}

export type Iwt2CloudSlot = {
  savedAt: number
  character: Iwt2Character
  inventory: Iwt2InventoryItem[]
  collectionLog: Iwt2CollectionLog
}

export type Iwt2Save = {
  version: 1
  updatedAt: number
  character: Iwt2Character
  inventory: Iwt2InventoryItem[]
  collectionLog: Iwt2CollectionLog
  cloudSlot?: Iwt2CloudSlot
}

const IWT2_SAVE_KEY = 'i-want-to-heal-2:save:v1'

export function createDefaultIwt2Save(): Iwt2Save {
  return {
    version: 1,
    updatedAt: Date.now(),
    character: {
      name: 'Healer',
      level: 1,
      experience: 0,
      healerStyle: 'dawnweaver',
      armorPalette: 'guild_green',
    },
    inventory: [],
    collectionLog: {
      bossKills: {},
      dropsFound: {},
    },
  }
}

function normalizeSave(value: unknown): Iwt2Save {
  if (!value || typeof value !== 'object') return createDefaultIwt2Save()
  const candidate = value as Partial<Iwt2Save>
  if (candidate.version !== 1) return createDefaultIwt2Save()
  return {
    version: 1,
    updatedAt: typeof candidate.updatedAt === 'number' ? candidate.updatedAt : Date.now(),
    character: {
      name: candidate.character?.name || 'Healer',
      level: Math.max(1, Math.floor(candidate.character?.level ?? 1)),
      experience: Math.max(0, Math.floor(candidate.character?.experience ?? 0)),
      healerStyle: asIwt2HealerId(candidate.character?.healerStyle),
      armorPalette: asIwt2ArmorPaletteId(candidate.character?.armorPalette),
    },
    inventory: Array.isArray(candidate.inventory) ? candidate.inventory : [],
    collectionLog: {
      bossKills: candidate.collectionLog?.bossKills ?? {},
      dropsFound: candidate.collectionLog?.dropsFound ?? {},
    },
    cloudSlot: normalizeCloudSlot(candidate.cloudSlot),
  }
}

export function loadIwt2Save(): Iwt2Save {
  try {
    return normalizeSave(JSON.parse(window.localStorage.getItem(IWT2_SAVE_KEY) ?? 'null'))
  } catch {
    return createDefaultIwt2Save()
  }
}

export function writeIwt2Save(save: Iwt2Save) {
  window.localStorage.setItem(IWT2_SAVE_KEY, JSON.stringify({
    ...save,
    updatedAt: Date.now(),
  }))
}

export function recordIwt2BossKill(save: Iwt2Save, bossId: string): Iwt2Save {
  const drop = bossDropFor(bossId)
  return {
    ...save,
    updatedAt: Date.now(),
    character: {
      ...save.character,
      experience: save.character.experience + 125,
      level: Math.max(save.character.level, 1 + Math.floor((save.character.experience + 125) / 500)),
    },
    inventory: [
      ...save.inventory,
      {
        id: `${drop.id}-${Date.now()}`,
        name: drop.name,
        quantity: 1,
        rarity: 'common',
      },
    ],
    collectionLog: {
      ...save.collectionLog,
      bossKills: {
        ...save.collectionLog.bossKills,
        [bossId]: (save.collectionLog.bossKills[bossId] ?? 0) + 1,
      },
      dropsFound: {
        ...save.collectionLog.dropsFound,
        [drop.id]: (save.collectionLog.dropsFound[drop.id] ?? 0) + 1,
      },
    },
  }
}

export function updateIwt2CharacterSettings(
  save: Iwt2Save,
  settings: Partial<Pick<Iwt2Save['character'], 'name' | 'healerStyle' | 'armorPalette'>>,
): Iwt2Save {
  return {
    ...save,
    updatedAt: Date.now(),
    character: {
      ...save.character,
      ...settings,
      name: normalizeCharacterName(settings.name ?? save.character.name),
      healerStyle: asIwt2HealerId(settings.healerStyle ?? save.character.healerStyle),
      armorPalette: asIwt2ArmorPaletteId(settings.armorPalette ?? save.character.armorPalette),
    },
  }
}

export function snapshotIwt2CloudSlot(save: Iwt2Save): Iwt2Save {
  return {
    ...save,
    updatedAt: Date.now(),
    cloudSlot: {
      savedAt: Date.now(),
      character: { ...save.character },
      inventory: save.inventory.map((item) => ({ ...item })),
      collectionLog: {
        bossKills: { ...save.collectionLog.bossKills },
        dropsFound: { ...save.collectionLog.dropsFound },
      },
    },
  }
}

export function restoreIwt2CloudSlot(save: Iwt2Save): Iwt2Save {
  if (!save.cloudSlot) return save
  return {
    ...save,
    updatedAt: Date.now(),
    character: { ...save.cloudSlot.character },
    inventory: save.cloudSlot.inventory.map((item) => ({ ...item })),
    collectionLog: {
      bossKills: { ...save.cloudSlot.collectionLog.bossKills },
      dropsFound: { ...save.cloudSlot.collectionLog.dropsFound },
    },
  }
}

function bossDropFor(bossId: string): { id: string, name: string } {
  if (bossId === 'yian-kut-ku') return { id: 'yian-kut-ku-scale', name: 'Yian Kut Ku Scale' }
  if (bossId === 'great-jaggi') return { id: 'great-jaggi-hide', name: 'Great Jaggi Hide' }
  if (bossId === 'khezu') return { id: 'khezu-pearl', name: 'Khezu Pearl' }
  return { id: 'raw-bulldrome-coin', name: 'Raw Bulldrome Coin' }
}

function asIwt2ArmorPaletteId(value: unknown): Iwt2ArmorPaletteId {
  return value === 'sun_gold'
    || value === 'ember_red'
    || value === 'moon_blue'
    || value === 'guild_green'
    ? value
    : 'guild_green'
}

function normalizeCharacterName(name: string): string {
  const trimmed = name.trim().slice(0, 18)
  return trimmed || 'Healer'
}

function normalizeCloudSlot(value: unknown): Iwt2CloudSlot | undefined {
  if (!value || typeof value !== 'object') return undefined
  const candidate = value as Partial<Iwt2CloudSlot>
  if (!candidate.character || !candidate.collectionLog) return undefined
  return {
    savedAt: typeof candidate.savedAt === 'number' ? candidate.savedAt : Date.now(),
    character: {
      name: normalizeCharacterName(candidate.character.name ?? 'Healer'),
      level: Math.max(1, Math.floor(candidate.character.level ?? 1)),
      experience: Math.max(0, Math.floor(candidate.character.experience ?? 0)),
      healerStyle: asIwt2HealerId(candidate.character.healerStyle),
      armorPalette: asIwt2ArmorPaletteId(candidate.character.armorPalette),
    },
    inventory: Array.isArray(candidate.inventory) ? candidate.inventory : [],
    collectionLog: {
      bossKills: candidate.collectionLog.bossKills ?? {},
      dropsFound: candidate.collectionLog.dropsFound ?? {},
    },
  }
}
