import {
  ARENA_PRIEST_SPELL_BAR,
  SPELLS,
  type SpellSlot,
} from './actionBoss/actionCombatSimulation'
import { SPELL_MANA_COSTS } from './actionCombatCore'

export type ArenaTeamId = 'player' | 'opponent'
export type ArenaPhase = 'setup' | 'fighting' | 'upgrade' | 'complete'
export type ArenaUpgradeId =
  | 'all-target'
  | 'all-cost'
  | 'all-cooldown'
  | `slot-${SpellSlot}-cost`
  | `slot-${SpellSlot}-cooldown`
  | 'slot-1-renew'
  | 'slot-1-shield'
  | 'slot-2-shield'
  | 'slot-2-duration'
  | 'slot-3-half-shield'
  | 'slot-3-renew'
  | 'slot-4-renew'
  | 'slot-5-renew'
  | 'slot-5-shield'
  | 'stored-momentum'
  | 'wide-radiance'
  | 'dense-shields'
  | 'atonement'

export type ArenaUpgrade = {
  id: ArenaUpgradeId
  label: string
  scope: string
  description: string
  cost: number
}

export type ArenaMatchState = {
  phase: ArenaPhase
  round: number
  playerName: string
  opponentName: string
  playerWins: number
  opponentWins: number
  playerCredits: number
  opponentCredits: number
  playerUpgrades: ArenaUpgradeId[]
  opponentUpgrades: ArenaUpgradeId[]
  history: string[]
}

const FALLBACK_SPELL_NAMES: Partial<Record<SpellSlot, string>> = {
  1: 'Smite',
  2: 'Power Word: Fortitude',
  3: 'Shadow Word: Pain',
  4: 'Power Word: Shield',
  5: 'Renew',
  6: 'Mind Blast',
  7: 'Heal',
  8: 'Mind Flay',
  9: 'Flash Heal',
}

function getSlotCostUpgradeId(slot: SpellSlot): ArenaUpgradeId {
  return `slot-${slot}-cost`
}

function getSlotCooldownUpgradeId(slot: SpellSlot): ArenaUpgradeId {
  return `slot-${slot}-cooldown`
}

function createSlotEconomyUpgrades(slot: SpellSlot): ArenaUpgrade[] {
  const name = getArenaSpellName(slot)
  return [
    {
      id: getSlotCostUpgradeId(slot),
      label: `${name}: -25% Mana Cost`,
      scope: `Slot ${slot}`,
      description: `${name} costs 25% less mana.`,
      cost: 1,
    },
    {
      id: getSlotCooldownUpgradeId(slot),
      label: `${name}: -25% Cooldown`,
      scope: `Slot ${slot}`,
      description: `${name} cooldown recovers 25% faster.`,
      cost: 1,
    },
  ]
}

const ARENA_UPGRADES: ArenaUpgrade[] = [
  {
    id: 'all-target',
    label: 'Every Slot: +1 Target',
    scope: 'Every Slot',
    description: 'Friendly ClaudeCraft priest spells reach one extra ally.',
    cost: 2,
  },
  {
    id: 'all-cost',
    label: 'Every Slot: -25% Cost',
    scope: 'Every Slot',
    description: 'All spell energy costs are reduced by 25%.',
    cost: 1,
  },
  {
    id: 'all-cooldown',
    label: 'Every Slot: -25% Cooldown',
    scope: 'Every Slot',
    description: 'All spell cooldowns recover faster.',
    cost: 1,
  },
  {
    id: 'slot-1-renew',
    label: `${getArenaSpellName(1)} Applies Renew`,
    scope: 'Slot 1',
    description: 'Slot 1 also applies Renew to its targets.',
    cost: 2,
  },
  {
    id: 'slot-1-shield',
    label: `${getArenaSpellName(1)} Applies Shield`,
    scope: 'Slot 1',
    description: 'Slot 1 also grants a shield.',
    cost: 2,
  },
  ...createSlotEconomyUpgrades(1),
  {
    id: 'slot-2-shield',
    label: `${getArenaSpellName(2)} Applies Shield`,
    scope: 'Slot 2',
    description: 'Slot 2 also grants a shield.',
    cost: 2,
  },
  {
    id: 'slot-2-duration',
    label: `${getArenaSpellName(2)} Double Duration`,
    scope: 'Slot 2',
    description: 'Slot 2 Renew lasts twice as long.',
    cost: 2,
  },
  ...createSlotEconomyUpgrades(2),
  {
    id: 'slot-3-half-shield',
    label: `${getArenaSpellName(3)} Applies 50% Shield`,
    scope: 'Slot 3',
    description: 'Slot 3 also grants a half-strength shield.',
    cost: 2,
  },
  {
    id: 'slot-3-renew',
    label: `${getArenaSpellName(3)} Applies Renew`,
    scope: 'Slot 3',
    description: 'Slot 3 also applies Renew to healed targets.',
    cost: 2,
  },
  ...createSlotEconomyUpgrades(3),
  {
    id: 'slot-4-renew',
    label: `${getArenaSpellName(4)} Applies Renew`,
    scope: 'Slot 4',
    description: 'Slot 4 also applies Renew.',
    cost: 2,
  },
  ...createSlotEconomyUpgrades(4),
  {
    id: 'slot-5-renew',
    label: `${getArenaSpellName(5)} Applies Renew`,
    scope: 'Slot 5',
    description: 'Slot 5 also applies Renew.',
    cost: 2,
  },
  {
    id: 'slot-5-shield',
    label: `${getArenaSpellName(5)} Applies Shield`,
    scope: 'Slot 5',
    description: 'Slot 5 also grants a shield.',
    cost: 2,
  },
  ...createSlotEconomyUpgrades(5),
  ...createSlotEconomyUpgrades(6),
  ...createSlotEconomyUpgrades(7),
  ...createSlotEconomyUpgrades(8),
  ...createSlotEconomyUpgrades(9),
  ...createSlotEconomyUpgrades(10),
  {
    id: 'stored-momentum',
    label: 'Stored Momentum',
    scope: 'Misc',
    description: 'After 5 spell casts, the next cast is free.',
    cost: 1,
  },
  {
    id: 'atonement',
    label: 'Atonement',
    scope: 'Priest',
    description: 'Smite and Shadow Word: Pain heal the lowest-health ally for 100% of damage dealt.',
    cost: 3,
  },
  {
    id: 'wide-radiance',
    label: 'Stronger Heal',
    scope: 'Misc',
    description: 'Heal is 25% stronger.',
    cost: 1,
  },
  {
    id: 'dense-shields',
    label: 'Dense Shields',
    scope: 'Misc',
    description: 'Shields absorb 25% more damage.',
    cost: 1,
  },
]

export function getArenaUpgrades() {
  return ARENA_UPGRADES
}

export function getArenaSpellName(slot: SpellSlot) {
  return SPELLS[slot]?.name || FALLBACK_SPELL_NAMES[slot] || `Slot ${slot}`
}

export function getArenaSpellCostMultiplier(upgrades: ArenaUpgradeId[], spell: SpellSlot) {
  let multiplier = upgrades.includes('all-cost') ? 0.75 : 1
  if (upgrades.includes(getSlotCostUpgradeId(spell))) multiplier *= 0.75
  return multiplier
}

export function getArenaSpellCooldownMultiplier(upgrades: ArenaUpgradeId[], spell: SpellSlot) {
  let multiplier = upgrades.includes('all-cooldown') ? 0.75 : 1
  if (upgrades.includes(getSlotCooldownUpgradeId(spell))) multiplier *= 0.75
  return multiplier
}

export function getArenaSpellLoadout() {
  return ARENA_PRIEST_SPELL_BAR.map((slot) => ({
    slot,
    name: getArenaSpellName(slot),
    cost: SPELL_MANA_COSTS[slot],
    cooldown: SPELLS[slot]?.cooldown ?? 0,
  }))
}

export function createArenaMatchState(playerName = 'Action Healer'): ArenaMatchState {
  return {
    phase: 'setup',
    round: 1,
    playerName,
    opponentName: 'Rival Five',
    playerWins: 0,
    opponentWins: 0,
    playerCredits: 0,
    opponentCredits: 0,
    playerUpgrades: [],
    opponentUpgrades: [],
    history: [],
  }
}

export function resolveArenaRoundWinner(
  match: ArenaMatchState,
  winner: 'player' | 'opponent',
  elapsedSeconds: number,
): ArenaMatchState {
  const playerWon = winner === 'player'
  const playerWins = match.playerWins + (playerWon ? 1 : 0)
  const opponentWins = match.opponentWins + (playerWon ? 0 : 1)
  const complete = playerWins >= 3 || opponentWins >= 3
  const winnerName = playerWon ? match.playerName : match.opponentName
  const playerPointAward = playerWon ? 3 : 4
  const opponentPointAward = playerWon ? 4 : 3
  const opponentDraft = complete
    ? { upgrades: match.opponentUpgrades, credits: match.opponentCredits + opponentPointAward, picked: null }
    : pickOpponentUpgrade(match.opponentUpgrades, match.opponentCredits + opponentPointAward)

  return {
    ...match,
    phase: complete ? 'complete' : 'upgrade',
    round: complete ? match.round : match.round + 1,
    playerWins,
    opponentWins,
    playerCredits: match.playerCredits + playerPointAward,
    opponentCredits: opponentDraft.credits,
    opponentUpgrades: opponentDraft.upgrades,
    history: [
      `${winnerName} won round ${match.round} in ${elapsedSeconds.toFixed(1)}s.`,
      ...(opponentDraft.picked ? [`${match.opponentName} drafted ${getUpgradeLabel(opponentDraft.picked)}.`] : []),
      ...match.history,
    ].slice(0, 6),
  }
}

export function buyArenaUpgrade(match: ArenaMatchState, upgradeId: ArenaUpgradeId): ArenaMatchState {
  const upgrade = ARENA_UPGRADES.find((item) => item.id === upgradeId)
  if (!upgrade) return match

  if (match.playerUpgrades.includes(upgradeId)) {
    return {
      ...match,
      playerCredits: match.playerCredits + upgrade.cost,
      playerUpgrades: match.playerUpgrades.filter((id) => id !== upgradeId),
      history: [`${match.playerName} removed ${upgrade.label}.`, ...match.history].slice(0, 6),
    }
  }

  if (match.playerCredits < upgrade.cost) return match

  return {
    ...match,
    playerCredits: match.playerCredits - upgrade.cost,
    playerUpgrades: [...match.playerUpgrades, upgradeId],
    history: [`${match.playerName} drafted ${upgrade.label}.`, ...match.history].slice(0, 6),
  }
}

export function startNextArenaRound(match: ArenaMatchState): ArenaMatchState {
  return {
    ...match,
    phase: 'fighting',
  }
}

export function getArenaAvailableUpgrades(match: ArenaMatchState) {
  return ARENA_UPGRADES.map((upgrade) => ({
    ...upgrade,
    owned: match.playerUpgrades.includes(upgrade.id),
    affordable: match.playerCredits >= upgrade.cost,
  }))
}

function pickOpponentUpgrade(upgrades: ArenaUpgradeId[], credits: number) {
  const priority: ArenaUpgradeId[] = [
    'all-cooldown',
    'wide-radiance',
    'all-cost',
    'slot-1-cost',
    'slot-1-cooldown',
    'slot-3-cost',
    'slot-3-cooldown',
    'slot-4-renew',
    'dense-shields',
    'all-target',
    'slot-3-half-shield',
    'stored-momentum',
  ]
  const picked = priority.find((id) => {
    const upgrade = ARENA_UPGRADES.find((item) => item.id === id)
    return upgrade && !upgrades.includes(id) && credits >= upgrade.cost
  }) ?? null
  if (!picked) return { upgrades, credits, picked }

  const cost = ARENA_UPGRADES.find((upgrade) => upgrade.id === picked)?.cost ?? 0
  return {
    upgrades: [...upgrades, picked],
    credits: credits - cost,
    picked,
  }
}

function getUpgradeLabel(id: ArenaUpgradeId) {
  return ARENA_UPGRADES.find((upgrade) => upgrade.id === id)?.label ?? id
}
