import type { PlayerClass } from './claudeCraftTypes'

export type TalentTree = 'class' | 'spec'
export type TalentKind = 'passive' | 'active' | 'choice'
export type TalentRole = 'tank' | 'healer' | 'dps'
type Role = TalentRole
type SpecDef = TalentSpec
type Gate = Pick<TalentNode, 'requires' | 'pointsGate'>

export type AbilityModifier = {
  castPct: number
  cooldownPct: number
  costPct: number
  dmgPct: number
  flatDmg: number
}

export type TalentEffect = {
  stats?: {
    str?: number
    agi?: number
    sta?: number
    int?: number
    spi?: number
    armor?: number
    ap?: number
    crit?: number
    dodge?: number
    apPct?: number
    staPct?: number
    armorPct?: number
    maxHpPct?: number
  }
  ability?: Array<{ ability: string } & Partial<AbilityModifier>>
  global?: Partial<TalentModifiers['global']>
  grant?: { ability: string, rank?: number }
}

export type TalentChoiceOption = {
  id: string
  name: string
  description: string
  icon: string
  effect: TalentEffect
}

export type TalentNode = {
  id: string
  tree: TalentTree
  specId?: string
  kind: TalentKind
  maxRank: number
  requires?: string[]
  pointsGate?: number
  choices?: TalentChoiceOption[]
  effect?: TalentEffect
  icon: string
  name: string
  description: string
  row: number
  col: number
}

export type TalentSpec = {
  id: string
  class: PlayerClass
  name: string
  role: TalentRole
  icon: string
  description: string
  signature: string
  mastery: { name: string, description: string, effect: TalentEffect }
}

export type ClassTalents = {
  class: PlayerClass
  nodes: TalentNode[]
  specs: TalentSpec[]
}

export type TalentAllocation = {
  spec: string | null
  ranks: Record<string, number>
  choices: Record<string, string>
}

export type TalentModifiers = {
  spec: string | null
  role: TalentRole | null
  abilities: Record<string, AbilityModifier>
  global: {
    healPct: number
    meleeDmgPct: number
    spellDmgPct: number
    threatPct: number
  }
  grants: Array<{ ability: string, rank: number }>
}

export const FIRST_TALENT_LEVEL = 10
export const MAX_TALENT_LEVEL = 20

const EMPTY_ABILITY_MOD: AbilityModifier = {
  castPct: 0,
  cooldownPct: 0,
  costPct: 0,
  dmgPct: 0,
  flatDmg: 0,
}

export function emptyTalentAllocation(): TalentAllocation {
  return { spec: null, ranks: {}, choices: {} }
}

export function normalizeTalentAllocation(raw: unknown, classId: PlayerClass): TalentAllocation {
  const parsed = raw && typeof raw === 'object' ? raw as Partial<TalentAllocation> : {}
  const talents = talentsFor(classId)
  const spec = typeof parsed.spec === 'string' && talents?.specs.some((candidate) => candidate.id === parsed.spec)
    ? parsed.spec
    : null
  const nodeIds = new Set(talents?.nodes.map((node) => node.id) ?? [])
  const ranks: Record<string, number> = {}
  if (parsed.ranks && typeof parsed.ranks === 'object') {
    for (const [id, rank] of Object.entries(parsed.ranks)) {
      if (!nodeIds.has(id)) continue
      ranks[id] = Math.max(0, Math.floor(Number(rank)))
    }
  }
  const choices: Record<string, string> = {}
  if (parsed.choices && typeof parsed.choices === 'object') {
    for (const [id, choiceId] of Object.entries(parsed.choices)) {
      if (nodeIds.has(id) && typeof choiceId === 'string') choices[id] = choiceId
    }
  }
  return { spec, ranks, choices }
}

export function talentPointsAtLevel(level: number): number {
  return Math.max(0, Math.min(level, MAX_TALENT_LEVEL) - (FIRST_TALENT_LEVEL - 1))
}

export function pointsSpent(alloc: TalentAllocation): number {
  return Object.values(alloc.ranks).reduce((sum, rank) => sum + Math.max(0, rank), 0)
}

export function talentsFor(classId: PlayerClass | string | undefined): ClassTalents | null {
  if (classId === 'paladin' || classId === 'priest' || classId === 'shaman' || classId === 'druid') return TALENTS[classId]
  return null
}

export function getTalentSpec(classId: PlayerClass | string | undefined, specId: string | null | undefined) {
  return talentsFor(classId)?.specs.find((spec) => spec.id === specId) ?? null
}

export function validateTalentAllocation(classId: PlayerClass, alloc: TalentAllocation, totalPoints: number): { ok: boolean, reason?: string } {
  const talents = talentsFor(classId)
  if (!talents) return { ok: false, reason: 'No talents for class.' }
  if (pointsSpent(alloc) > totalPoints) return { ok: false, reason: 'Not enough talent points.' }
  const nodes = nodeIndex(talents)
  for (const [nodeId, rank] of Object.entries(alloc.ranks)) {
    const node = nodes.get(nodeId)
    if (!node) return { ok: false, reason: 'Unknown talent.' }
    if (rank < 0 || rank > node.maxRank) return { ok: false, reason: 'Invalid talent rank.' }
    if (node.tree === 'spec' && node.specId !== alloc.spec) return { ok: false, reason: 'Wrong specialization tree.' }
    if ((node.pointsGate ?? 0) > pointsAboveRow(talents, alloc, node)) return { ok: false, reason: 'Spend more points above this row.' }
    for (const required of node.requires ?? []) {
      if ((alloc.ranks[required] ?? 0) <= 0) return { ok: false, reason: 'Missing prerequisite.' }
    }
    if (node.kind === 'choice') {
      const chosen = alloc.choices[node.id]
      if (rank > 0 && !node.choices?.some((choice) => choice.id === chosen)) return { ok: false, reason: 'Choose a talent option.' }
    }
  }
  return { ok: true }
}

export function allocateTalentPoint(classId: PlayerClass, alloc: TalentAllocation, nodeId: string, totalPoints: number, choiceId?: string): { allocation: TalentAllocation, ok: boolean, reason?: string } {
  const talents = talentsFor(classId)
  const node = talents?.nodes.find((candidate) => candidate.id === nodeId)
  if (!talents || !node) return { allocation: alloc, ok: false, reason: 'Unknown talent.' }
  if (!alloc.spec) return { allocation: alloc, ok: false, reason: 'Pick a specialization first.' }
  if (pointsSpent(alloc) >= totalPoints) return { allocation: alloc, ok: false, reason: 'No talent points available.' }
  const next: TalentAllocation = {
    spec: alloc.spec,
    ranks: { ...alloc.ranks, [nodeId]: (alloc.ranks[nodeId] ?? 0) + 1 },
    choices: { ...alloc.choices },
  }
  if (node.kind === 'choice') {
    const selected = choiceId ?? node.choices?.[0]?.id
    if (selected) next.choices[nodeId] = selected
  }
  const validation = validateTalentAllocation(classId, next, totalPoints)
  return validation.ok ? { allocation: next, ok: true } : { allocation: alloc, ok: false, reason: validation.reason }
}

export function setTalentSpec(classId: PlayerClass, alloc: TalentAllocation, specId: string): TalentAllocation {
  const talents = talentsFor(classId)
  if (!talents?.specs.some((spec) => spec.id === specId)) return alloc
  return { spec: specId, ranks: {}, choices: {} }
}

export function computeTalentModifiers(classId: PlayerClass | string | undefined, alloc: TalentAllocation): TalentModifiers {
  const talents = talentsFor(classId)
  const mods = emptyTalentModifiers()
  if (!talents) return mods
  const spec = alloc.spec ? talents.specs.find((candidate) => candidate.id === alloc.spec) ?? null : null
  if (spec) {
    mods.spec = spec.id
    mods.role = spec.role
    mods.grants.push({ ability: spec.signature, rank: 1 })
    accumulate(mods, spec.mastery.effect, 1)
  }
  const nodes = nodeIndex(talents)
  for (const [nodeId, rank] of Object.entries(alloc.ranks)) {
    const node = nodes.get(nodeId)
    if (!node || rank <= 0) continue
    if (node.tree === 'spec' && node.specId !== alloc.spec) continue
    if (node.kind === 'choice') {
      const choice = node.choices?.find((candidate) => candidate.id === alloc.choices[node.id])
      if (choice) accumulate(mods, choice.effect, 1)
    } else {
      accumulate(mods, node.effect, rank)
    }
  }
  return mods
}

export function getEmptyClaudeCraftAbilityModifier(): AbilityModifier {
  return EMPTY_ABILITY_MOD
}

function emptyTalentModifiers(): TalentModifiers {
  return {
    spec: null,
    role: null,
    abilities: {},
    global: { healPct: 0, meleeDmgPct: 0, spellDmgPct: 0, threatPct: 0 },
    grants: [],
  }
}

function accumulate(mods: TalentModifiers, effect: TalentEffect | undefined, rank: number) {
  if (!effect) return
  if (effect.global) {
    mods.global.healPct += (effect.global.healPct ?? 0) * rank
    mods.global.meleeDmgPct += (effect.global.meleeDmgPct ?? 0) * rank
    mods.global.spellDmgPct += (effect.global.spellDmgPct ?? 0) * rank
    mods.global.threatPct += (effect.global.threatPct ?? 0) * rank
  }
  for (const ability of effect.ability ?? []) {
    const current = mods.abilities[ability.ability] ?? { ...EMPTY_ABILITY_MOD }
    current.castPct += (ability.castPct ?? 0) * rank
    current.cooldownPct += (ability.cooldownPct ?? 0) * rank
    current.costPct += (ability.costPct ?? 0) * rank
    current.dmgPct += (ability.dmgPct ?? 0) * rank
    current.flatDmg += (ability.flatDmg ?? 0) * rank
    mods.abilities[ability.ability] = current
  }
  if (effect.grant) mods.grants.push({ ability: effect.grant.ability, rank: effect.grant.rank ?? 1 })
}

function pointsAboveRow(talents: ClassTalents, alloc: TalentAllocation, node: TalentNode) {
  return talents.nodes.reduce((sum, candidate) => {
    if (candidate.tree !== node.tree || candidate.row >= node.row) return sum
    if (candidate.tree === 'spec' && candidate.specId !== alloc.spec) return sum
    return sum + (alloc.ranks[candidate.id] ?? 0)
  }, 0)
}

function nodeIndex(talents: ClassTalents) {
  return new Map(talents.nodes.map((node) => [node.id, node]))
}

function passive(id: string, tree: TalentTree, specId: string | undefined, maxRank: number, effect: TalentEffect, icon: string, name: string, description: string, row: number, col: number, gate: Gate = {}): TalentNode {
  return { id, tree, ...(specId ? { specId } : {}), kind: 'passive', maxRank, effect, icon, name, description, row, col, ...gate }
}

function active(id: string, tree: TalentTree, specId: string | undefined, effect: TalentEffect, icon: string, name: string, description: string, row: number, col: number, gate: Gate = {}): TalentNode {
  return { id, tree, ...(specId ? { specId } : {}), kind: 'active', maxRank: 1, effect, icon, name, description, row, col, ...gate }
}

function choice(id: string, tree: TalentTree, specId: string | undefined, icon: string, name: string, description: string, row: number, col: number, choices: TalentChoiceOption[], gate: Gate = {}): TalentNode {
  return { id, tree, ...(specId ? { specId } : {}), kind: 'choice', maxRank: 1, icon, name, description, row, col, choices, ...gate }
}

function spec(id: string, cls: PlayerClass, name: string, role: Role, icon: string, description: string, signature: string, masteryName: string, masteryDescription: string, effect: TalentEffect): SpecDef {
  return { id, class: cls, name, role, icon, description, signature, mastery: { name: masteryName, description: masteryDescription, effect } }
}

const PALADIN_CLASS: TalentNode[] = [
  passive('pal_divine_strength', 'class', undefined, 3, { stats: { str: 2 } }, '+', 'Divine Strength', 'Increases your Strength by 2 per rank.', 0, 0),
  passive('pal_spiritual_focus', 'class', undefined, 3, { stats: { spi: 2 }, global: { healPct: 0.02 } }, '*', 'Spiritual Focus', 'Increases Spirit by 2 and healing done by 2% per rank.', 0, 2),
  passive('pal_imp_devotion_aura', 'class', undefined, 2, { ability: [{ ability: 'devotion_aura', dmgPct: 0.20 }], stats: { armorPct: 0.03 } }, '#', 'Improved Devotion Aura', 'Increases your armor by 3% per rank and strengthens Devotion Aura.', 1, 0, { requires: ['pal_divine_strength'] }),
  passive('pal_benediction', 'class', undefined, 2, { ability: [{ ability: 'seal_of_righteousness', costPct: -0.08 }, { ability: 'judgement', costPct: -0.08 }] }, 'v', 'Benediction', 'Reduces the mana cost of Seal of Righteousness and Judgement by 8% per rank.', 1, 1, { pointsGate: 2 }),
  passive('pal_precision', 'class', undefined, 3, { stats: { crit: 0.01 } }, 'x', 'Conviction', 'Increases your critical strike chance by 1% per rank.', 1, 2, { requires: ['pal_spiritual_focus'] }),
  choice('pal_holy_calling', 'class', undefined, '@', 'Holy Calling', 'Choose one paladin emphasis.', 2, 1, [
    { id: 'pal_calling_light', name: 'Healing Light', icon: '+', description: 'Increases healing done by 6%.', effect: { global: { healPct: 0.06 } } },
    { id: 'pal_calling_guardian', name: 'Guardian Favor', icon: '#', description: 'Increases armor by 8% and dodge by 2%.', effect: { stats: { armorPct: 0.08, dodge: 0.02 } } },
    { id: 'pal_calling_crusader', name: 'Crusader Zeal', icon: 'x', description: 'Increases melee ability damage by 6%.', effect: { global: { meleeDmgPct: 0.06 } } },
  ], { pointsGate: 5 }),
  active('pal_divine_favor', 'class', undefined, { grant: { ability: 'divine_protection' } }, 'O', 'Divine Favor', 'Grants early access to Divine Protection.', 3, 0, { pointsGate: 8, requires: ['pal_imp_devotion_aura'] }),
  passive('pal_sanctified_light', 'class', undefined, 2, { stats: { int: 3, maxHpPct: 0.04 } }, '*', 'Sanctified Light', 'Increases Intellect by 3 and maximum health by 4% per rank.', 3, 2, { pointsGate: 8, requires: ['pal_holy_calling'] }),
]

const PALADIN_SPECS: SpecDef[] = [
  spec('holy', 'paladin', 'Holy', 'healer', '+', 'A devoted healer who turns the Light into steady single-target recovery.', 'flash_of_light', 'Illumination', 'Increases all healing done by 12%.', { global: { healPct: 0.12 } }),
  spec('protection', 'paladin', 'Protection', 'tank', '#', 'A shield-bearing defender who converts Holy power into threat and mitigation.', 'righteous_fury', 'Holy Shielding', 'Increases threat by 25% and armor by 10%.', { global: { threatPct: 0.25 }, stats: { armorPct: 0.10 } }),
  spec('retribution', 'paladin', 'Retribution', 'dps', 'x', 'A holy warrior who judges enemies with weapon strikes and radiant burst.', 'judgement', 'Vengeance', 'Increases melee and spell ability damage by 6%.', { global: { meleeDmgPct: 0.06, spellDmgPct: 0.06 } }),
]

const PALADIN_SPEC_NODES: TalentNode[] = [
  passive('holy_imp_holy_light', 'spec', 'holy', 3, { ability: [{ ability: 'holy_light', dmgPct: 0.08 }] }, '+', 'Improved Holy Light', 'Increases Holy Light healing by 8% per rank.', 0, 0),
  passive('holy_divine_intellect', 'spec', 'holy', 3, { stats: { int: 3 } }, '*', 'Divine Intellect', 'Increases Intellect by 3 per rank.', 0, 2),
  passive('holy_flash_focus', 'spec', 'holy', 2, { ability: [{ ability: 'flash_of_light', castPct: -0.10, costPct: -0.08 }] }, '>', 'Flash Focus', 'Makes Flash of Light faster and cheaper by 10%/8% per rank.', 1, 0, { pointsGate: 2, requires: ['holy_imp_holy_light'] }),
  passive('holy_lay_blessing', 'spec', 'holy', 2, { ability: [{ ability: 'lay_on_hands', cooldownPct: -0.20 }] }, 'O', 'Improved Lay on Hands', 'Reduces Lay on Hands cooldown by 20% per rank.', 1, 2, { pointsGate: 2 }),
  choice('holy_choice', 'spec', 'holy', '@', 'Beacon Discipline', 'Choose one Holy refinement.', 2, 1, [
    { id: 'holy_choice_grace', name: 'Holy Grace', icon: '+', description: 'Increases healing by 8%.', effect: { global: { healPct: 0.08 } } },
    { id: 'holy_choice_judgement', name: 'Judgement of Light', icon: 'x', description: 'Judgement deals 20% more damage.', effect: { ability: [{ ability: 'judgement', dmgPct: 0.20 }] } },
    { id: 'holy_choice_devotion', name: 'Devoted Soul', icon: '#', description: 'Increases stamina by 8%.', effect: { stats: { staPct: 0.08 } } },
  ], { pointsGate: 5 }),
  passive('holy_light_mastery', 'spec', 'holy', 2, { global: { healPct: 0.06 }, stats: { crit: 0.01 } }, '*', 'Light Mastery', 'Increases healing by 6% and critical strike by 1% per rank.', 3, 1, { pointsGate: 8, requires: ['holy_choice'] }),

  passive('prot_redoubt', 'spec', 'protection', 3, { stats: { armorPct: 0.05 } }, '#', 'Redoubt', 'Increases armor by 5% per rank.', 0, 0),
  passive('prot_anticipation', 'spec', 'protection', 3, { stats: { dodge: 0.01 } }, 'o', 'Anticipation', 'Increases dodge chance by 1% per rank.', 0, 2),
  passive('prot_imp_righteous_fury', 'spec', 'protection', 2, { global: { threatPct: 0.10 }, ability: [{ ability: 'righteous_fury', costPct: -0.25 }] }, '!', 'Improved Righteous Fury', 'Increases threat by 10% and reduces Righteous Fury cost by 25% per rank.', 1, 0, { pointsGate: 2, requires: ['prot_redoubt'] }),
  passive('prot_guardians_favor', 'spec', 'protection', 2, { ability: [{ ability: 'divine_protection', cooldownPct: -0.15 }, { ability: 'hammer_of_justice', cooldownPct: -0.10 }] }, 'O', 'Guardian Favor', 'Reduces defensive cooldowns by 10-15% per rank.', 1, 2, { pointsGate: 2 }),
  choice('prot_choice', 'spec', 'protection', '@', 'Sanctuary', 'Choose one Protection refinement.', 2, 1, [
    { id: 'prot_choice_sanctuary', name: 'Blessing of Sanctuary', icon: '#', description: 'Increases armor by 12%.', effect: { stats: { armorPct: 0.12 } } },
    { id: 'prot_choice_reckoning', name: 'Reckoning', icon: 'x', description: 'Increases melee damage by 8%.', effect: { global: { meleeDmgPct: 0.08 } } },
    { id: 'prot_choice_ardent', name: 'Ardent Defender', icon: '+', description: 'Increases maximum health by 12%.', effect: { stats: { maxHpPct: 0.12 } } },
  ], { pointsGate: 5 }),
  passive('prot_holy_shield', 'spec', 'protection', 2, { ability: [{ ability: 'consecration', dmgPct: 0.12 }], global: { threatPct: 0.08 } }, '#', 'Holy Shield', 'Increases Consecration damage by 12% and threat by 8% per rank.', 3, 1, { pointsGate: 8, requires: ['prot_choice'] }),

  passive('ret_benediction', 'spec', 'retribution', 3, { ability: [{ ability: 'seal_of_righteousness', costPct: -0.08 }, { ability: 'judgement', costPct: -0.08 }] }, 'v', 'Benediction', 'Reduces core offensive costs by 8% per rank.', 0, 0),
  passive('ret_conviction', 'spec', 'retribution', 3, { stats: { crit: 0.01 } }, 'x', 'Conviction', 'Increases critical strike chance by 1% per rank.', 0, 2),
  passive('ret_imp_judgement', 'spec', 'retribution', 2, { ability: [{ ability: 'judgement', cooldownPct: -0.15, dmgPct: 0.10 }] }, '!', 'Improved Judgement', 'Reduces Judgement cooldown by 15% and increases damage by 10% per rank.', 1, 0, { pointsGate: 2, requires: ['ret_benediction'] }),
  passive('ret_seal_command', 'spec', 'retribution', 2, { ability: [{ ability: 'seal_of_righteousness', dmgPct: 0.20 }] }, 'x', 'Seal Command', 'Increases Seal of Righteousness damage by 20% per rank.', 1, 2, { pointsGate: 2 }),
  choice('ret_choice', 'spec', 'retribution', '@', 'Crusader Path', 'Choose one Retribution refinement.', 2, 1, [
    { id: 'ret_choice_sanctity', name: 'Sanctity Aura', icon: '*', description: 'Increases spell damage by 8%.', effect: { global: { spellDmgPct: 0.08 } } },
    { id: 'ret_choice_pursuit', name: 'Pursuit of Justice', icon: '>', description: 'Increases dodge by 3% and attack power by 10%.', effect: { stats: { dodge: 0.03, apPct: 0.10 } } },
    { id: 'ret_choice_vengeance', name: 'Vengeance', icon: 'x', description: 'Increases critical strike chance by 4%.', effect: { stats: { crit: 0.04 } } },
  ], { pointsGate: 5 }),
  passive('ret_crusader_strikes', 'spec', 'retribution', 2, { global: { meleeDmgPct: 0.06, spellDmgPct: 0.04 }, ability: [{ ability: 'exorcism', cooldownPct: -0.10 }] }, 'x', 'Crusader Strikes', 'Increases offensive damage and reduces Exorcism cooldown per rank.', 3, 1, { pointsGate: 8, requires: ['ret_choice'] }),
]

const PRIEST_CLASS: TalentNode[] = [
  passive('pri_wand_specialization', 'class', undefined, 3, { stats: { int: 1, spi: 1 } }, '/', 'Wand Specialization', 'Increases Intellect and Spirit by 1 per rank.', 0, 0),
  passive('pri_spirit_tap', 'class', undefined, 3, { stats: { spi: 3 } }, '*', 'Spirit Tap', 'Increases Spirit by 3 per rank.', 0, 2),
  passive('pri_imp_fortitude', 'class', undefined, 2, { ability: [{ ability: 'power_word_fortitude', dmgPct: 0.20 }], stats: { sta: 2 } }, '+', 'Improved Fortitude', 'Increases Stamina by 2 and strengthens Fortitude per rank.', 1, 0, { requires: ['pri_wand_specialization'] }),
  passive('pri_meditation', 'class', undefined, 2, { ability: [{ ability: 'lesser_heal', costPct: -0.08 }, { ability: 'heal', costPct: -0.08 }, { ability: 'flash_heal', costPct: -0.08 }] }, 'v', 'Meditation', 'Reduces healing spell costs by 8% per rank.', 1, 1, { pointsGate: 2 }),
  passive('pri_shadow_affinity', 'class', undefined, 3, { ability: [{ ability: 'shadow_word_pain', costPct: -0.05 }, { ability: 'mind_blast', costPct: -0.05 }] }, '*', 'Shadow Affinity', 'Reduces Shadow spell costs by 5% per rank.', 1, 2, { requires: ['pri_spirit_tap'] }),
  choice('pri_inner_calling', 'class', undefined, '@', 'Inner Calling', 'Choose one priest emphasis.', 2, 1, [
    { id: 'pri_calling_disc', name: 'Inner Focus', icon: '#', description: 'Power Word: Shield absorbs 18% more.', effect: { ability: [{ ability: 'power_word_shield', dmgPct: 0.18 }] } },
    { id: 'pri_calling_holy', name: 'Divine Fury', icon: '+', description: 'Increases healing by 8%.', effect: { global: { healPct: 0.08 } } },
    { id: 'pri_calling_shadow', name: 'Darkness', icon: '*', description: 'Increases spell damage by 8%.', effect: { global: { spellDmgPct: 0.08 } } },
  ], { pointsGate: 5 }),
  active('pri_desperate_prayer', 'class', undefined, { grant: { ability: 'flash_heal' } }, '+', 'Desperate Prayer', 'Grants early access to Flash Heal.', 3, 0, { pointsGate: 8, requires: ['pri_imp_fortitude'] }),
  passive('pri_enlightenment', 'class', undefined, 2, { stats: { int: 3, spi: 3 } }, '*', 'Enlightenment', 'Increases Intellect and Spirit by 3 per rank.', 3, 2, { pointsGate: 8, requires: ['pri_inner_calling'] }),
]

const PRIEST_SPECS: SpecDef[] = [
  spec('discipline', 'priest', 'Discipline', 'healer', '#', 'A mitigator who shields allies and heals through controlled efficiency.', 'power_word_shield', 'Focused Will', 'Increases healing and maximum health.', { global: { healPct: 0.08 }, stats: { maxHpPct: 0.08 } }),
  spec('holy', 'priest', 'Holy', 'healer', '+', 'A direct healer with strong throughput and restorative prayers.', 'flash_heal', 'Spiritual Healing', 'Increases all healing done by 14%.', { global: { healPct: 0.14 } }),
  spec('shadow', 'priest', 'Shadow', 'dps', '*', 'A damage caster built around Shadow damage over time and mind spells.', 'mind_flay', 'Shadowform', 'Increases spell damage by 12% and armor by 8%.', { global: { spellDmgPct: 0.12 }, stats: { armorPct: 0.08 } }),
]

const PRIEST_SPEC_NODES: TalentNode[] = [
  passive('disc_unbreakable_will', 'spec', 'discipline', 3, { stats: { sta: 2, spi: 1 } }, '#', 'Unbreakable Will', 'Increases Stamina by 2 and Spirit by 1 per rank.', 0, 0),
  passive('disc_twin_disciplines', 'spec', 'discipline', 3, { ability: [{ ability: 'power_word_shield', dmgPct: 0.08 }] }, '#', 'Twin Disciplines', 'Increases Power Word: Shield absorption by 8% per rank.', 0, 2),
  passive('disc_imp_shield', 'spec', 'discipline', 2, { ability: [{ ability: 'power_word_shield', cooldownPct: -0.15, costPct: -0.08 }] }, '#', 'Improved Power Word: Shield', 'Improves shield cooldown and cost per rank.', 1, 0, { pointsGate: 2, requires: ['disc_unbreakable_will'] }),
  passive('disc_mental_agility', 'spec', 'discipline', 2, { ability: [{ ability: 'renew', costPct: -0.10 }, { ability: 'power_word_shield', costPct: -0.10 }] }, 'v', 'Mental Agility', 'Reduces instant support spell costs by 10% per rank.', 1, 2, { pointsGate: 2 }),
  choice('disc_choice', 'spec', 'discipline', '@', 'Discipline Focus', 'Choose one Discipline refinement.', 2, 1, [
    { id: 'disc_choice_barrier', name: 'Borrowed Time', icon: '#', description: 'Shielding spells are stronger.', effect: { ability: [{ ability: 'power_word_shield', dmgPct: 0.25 }] } },
    { id: 'disc_choice_focus', name: 'Inner Focus', icon: '*', description: 'Healing spells cost 15% less.', effect: { ability: [{ ability: 'lesser_heal', costPct: -0.15 }, { ability: 'heal', costPct: -0.15 }, { ability: 'flash_heal', costPct: -0.15 }] } },
    { id: 'disc_choice_power', name: 'Power Infusion', icon: '+', description: 'Increases healing and spell damage by 6%.', effect: { global: { healPct: 0.06, spellDmgPct: 0.06 } } },
  ], { pointsGate: 5 }),
  passive('disc_penance', 'spec', 'discipline', 2, { global: { healPct: 0.05 }, ability: [{ ability: 'smite', dmgPct: 0.08 }] }, '+', 'Penance', 'Improves healing and Smite pressure per rank.', 3, 1, { pointsGate: 8, requires: ['disc_choice'] }),

  passive('holy_healing_focus', 'spec', 'holy', 3, { ability: [{ ability: 'lesser_heal', dmgPct: 0.06 }, { ability: 'heal', dmgPct: 0.06 }] }, '+', 'Healing Focus', 'Increases direct healing by 6% per rank.', 0, 0),
  passive('holy_renewal', 'spec', 'holy', 3, { ability: [{ ability: 'renew', dmgPct: 0.08 }] }, '+', 'Improved Renew', 'Increases Renew healing by 8% per rank.', 0, 2),
  passive('holy_divine_fury', 'spec', 'holy', 2, { ability: [{ ability: 'heal', castPct: -0.10 }, { ability: 'smite', castPct: -0.05 }] }, '>', 'Divine Fury', 'Makes Heal and Smite faster per rank.', 1, 0, { pointsGate: 2, requires: ['holy_healing_focus'] }),
  passive('holy_inspiration', 'spec', 'holy', 2, { stats: { armorPct: 0.05 }, global: { healPct: 0.03 } }, '#', 'Inspiration', 'Increases armor and healing per rank.', 1, 2, { pointsGate: 2 }),
  choice('holy_priest_choice', 'spec', 'holy', '@', 'Holy Word', 'Choose one Holy refinement.', 2, 1, [
    { id: 'holy_priest_choice_spirit', name: 'Spiritual Guidance', icon: '*', description: 'Increases Spirit by 10.', effect: { stats: { spi: 10 } } },
    { id: 'holy_priest_choice_nova', name: 'Holy Reach', icon: '+', description: 'Smite and Holy heals are 8% stronger.', effect: { global: { healPct: 0.08 }, ability: [{ ability: 'smite', dmgPct: 0.08 }] } },
    { id: 'holy_priest_choice_prayer', name: 'Healing Prayers', icon: 'v', description: 'Healing spells cost 12% less.', effect: { ability: [{ ability: 'lesser_heal', costPct: -0.12 }, { ability: 'heal', costPct: -0.12 }, { ability: 'flash_heal', costPct: -0.12 }] } },
  ], { pointsGate: 5 }),
  passive('holy_spiritual_healing', 'spec', 'holy', 2, { global: { healPct: 0.07 }, stats: { crit: 0.01 } }, '+', 'Spiritual Healing', 'Increases healing and crit per rank.', 3, 1, { pointsGate: 8, requires: ['holy_priest_choice'] }),

  passive('shadow_blackout', 'spec', 'shadow', 3, { ability: [{ ability: 'mind_blast', dmgPct: 0.06 }] }, '*', 'Blackout', 'Increases Mind Blast damage by 6% per rank.', 0, 0),
  passive('shadow_word_pain', 'spec', 'shadow', 3, { ability: [{ ability: 'shadow_word_pain', dmgPct: 0.08 }] }, '*', 'Improved Shadow Word: Pain', 'Increases Shadow Word: Pain damage by 8% per rank.', 0, 2),
  passive('shadow_mind_flay', 'spec', 'shadow', 2, { ability: [{ ability: 'mind_flay', dmgPct: 0.12, costPct: -0.08 }] }, '*', 'Improved Mind Flay', 'Improves Mind Flay damage and cost per rank.', 1, 0, { pointsGate: 2, requires: ['shadow_blackout'] }),
  passive('shadow_focus', 'spec', 'shadow', 2, { global: { spellDmgPct: 0.04 } }, 'x', 'Shadow Focus', 'Increases spell damage by 4% per rank.', 1, 2, { pointsGate: 2 }),
  choice('shadow_choice', 'spec', 'shadow', '@', 'Dark Arts', 'Choose one Shadow refinement.', 2, 1, [
    { id: 'shadow_choice_vampiric', name: 'Vampiric Embrace', icon: '+', description: 'Increases maximum health and spell damage.', effect: { stats: { maxHpPct: 0.08 }, global: { spellDmgPct: 0.04 } } },
    { id: 'shadow_choice_silence', name: 'Silence', icon: 'O', description: 'Mind Blast cooldown is reduced by 20%.', effect: { ability: [{ ability: 'mind_blast', cooldownPct: -0.20 }] } },
    { id: 'shadow_choice_darkness', name: 'Darkness', icon: '*', description: 'Increases spell damage by 10%.', effect: { global: { spellDmgPct: 0.10 } } },
  ], { pointsGate: 5 }),
  passive('shadow_shadowform', 'spec', 'shadow', 2, { global: { spellDmgPct: 0.07 }, stats: { armorPct: 0.05 } }, '*', 'Shadowform', 'Increases spell damage and armor per rank.', 3, 1, { pointsGate: 8, requires: ['shadow_choice'] }),
]

const SHAMAN_CLASS: TalentNode[] = [
  passive('sha_convection', 'class', undefined, 3, { ability: [{ ability: 'lightning_bolt', costPct: -0.05 }, { ability: 'earth_shock', costPct: -0.05 }] }, 'v', 'Convection', 'Reduces Lightning Bolt and Earth Shock costs by 5% per rank.', 0, 0),
  passive('sha_ancestral_knowledge', 'class', undefined, 3, { stats: { int: 2 } }, '*', 'Ancestral Knowledge', 'Increases Intellect by 2 per rank.', 0, 2),
  passive('sha_shielding', 'class', undefined, 2, { ability: [{ ability: 'lightning_shield', dmgPct: 0.15 }], stats: { armorPct: 0.03 } }, '#', 'Improved Lightning Shield', 'Strengthens Lightning Shield and armor per rank.', 1, 0, { requires: ['sha_convection'] }),
  passive('sha_thundering_strikes', 'class', undefined, 2, { stats: { crit: 0.015 } }, 'x', 'Thundering Strikes', 'Increases critical strike chance by 1.5% per rank.', 1, 1, { pointsGate: 2 }),
  passive('sha_tidal_focus', 'class', undefined, 3, { ability: [{ ability: 'healing_wave', costPct: -0.05 }] }, '+', 'Tidal Focus', 'Reduces Healing Wave cost by 5% per rank.', 1, 2, { requires: ['sha_ancestral_knowledge'] }),
  choice('sha_elemental_calling', 'class', undefined, '@', 'Elemental Calling', 'Choose one shaman emphasis.', 2, 1, [
    { id: 'sha_calling_elemental', name: 'Elemental Fury', icon: '*', description: 'Increases spell damage by 8%.', effect: { global: { spellDmgPct: 0.08 } } },
    { id: 'sha_calling_enhance', name: 'Flurry', icon: 'x', description: 'Increases melee ability damage by 8%.', effect: { global: { meleeDmgPct: 0.08 } } },
    { id: 'sha_calling_restoration', name: 'Healing Grace', icon: '+', description: 'Increases healing by 8%.', effect: { global: { healPct: 0.08 } } },
  ], { pointsGate: 5 }),
  active('sha_ghost_wolf', 'class', undefined, { grant: { ability: 'ghost_wolf' } }, '>', 'Improved Ghost Wolf', 'Grants early access to Ghost Wolf.', 3, 0, { pointsGate: 8, requires: ['sha_shielding'] }),
  passive('sha_natures_guidance', 'class', undefined, 2, { stats: { int: 3, sta: 3 } }, '+', 'Nature Guidance', 'Increases Intellect and Stamina by 3 per rank.', 3, 2, { pointsGate: 8, requires: ['sha_elemental_calling'] }),
]

const SHAMAN_SPECS: SpecDef[] = [
  spec('elemental', 'shaman', 'Elemental', 'dps', '*', 'A ranged caster who calls lightning, flame, and frost.', 'lightning_bolt', 'Elemental Fury', 'Increases spell damage and critical strike chance.', { global: { spellDmgPct: 0.10 }, stats: { crit: 0.02 } }),
  spec('enhancement', 'shaman', 'Enhancement', 'dps', 'x', 'A weapon fighter who channels the storm through melee swings.', 'stormstrike', 'Stormcaller', 'Increases melee ability damage and attack power.', { global: { meleeDmgPct: 0.10 }, stats: { ap: 10 } }),
  spec('restoration', 'shaman', 'Restoration', 'healer', '+', 'A healer using ancestral waves and efficient nature magic.', 'healing_wave', 'Purification', 'Increases healing done by 14%.', { global: { healPct: 0.14 } }),
]

const SHAMAN_SPEC_NODES: TalentNode[] = [
  passive('ele_concussion', 'spec', 'elemental', 3, { ability: [{ ability: 'lightning_bolt', dmgPct: 0.06 }, { ability: 'earth_shock', dmgPct: 0.06 }] }, '*', 'Concussion', 'Increases Lightning Bolt and Earth Shock damage by 6% per rank.', 0, 0),
  passive('ele_call_flame', 'spec', 'elemental', 3, { ability: [{ ability: 'flame_shock', dmgPct: 0.08 }] }, 'x', 'Call of Flame', 'Increases Flame Shock damage by 8% per rank.', 0, 2),
  passive('ele_reverberation', 'spec', 'elemental', 2, { ability: [{ ability: 'earth_shock', cooldownPct: -0.12 }, { ability: 'frost_shock', cooldownPct: -0.12 }] }, '>', 'Reverberation', 'Reduces Shock cooldowns by 12% per rank.', 1, 0, { pointsGate: 2, requires: ['ele_concussion'] }),
  passive('ele_elemental_focus', 'spec', 'elemental', 2, { ability: [{ ability: 'lightning_bolt', costPct: -0.10 }, { ability: 'flame_shock', costPct: -0.10 }] }, 'v', 'Elemental Focus', 'Reduces offensive spell costs by 10% per rank.', 1, 2, { pointsGate: 2 }),
  choice('ele_choice', 'spec', 'elemental', '@', 'Elemental Mastery', 'Choose one Elemental refinement.', 2, 1, [
    { id: 'ele_choice_mastery', name: 'Elemental Mastery', icon: '*', description: 'Increases spell damage by 10%.', effect: { global: { spellDmgPct: 0.10 } } },
    { id: 'ele_choice_devastation', name: 'Elemental Devastation', icon: 'x', description: 'Increases critical strike by 5%.', effect: { stats: { crit: 0.05 } } },
    { id: 'ele_choice_storm', name: 'Storm Reach', icon: '>', description: 'Lightning Bolt casts 20% faster.', effect: { ability: [{ ability: 'lightning_bolt', castPct: -0.20 }] } },
  ], { pointsGate: 5 }),
  passive('ele_lightning_mastery', 'spec', 'elemental', 2, { ability: [{ ability: 'lightning_bolt', castPct: -0.08, dmgPct: 0.10 }] }, '*', 'Lightning Mastery', 'Improves Lightning Bolt cast and damage per rank.', 3, 1, { pointsGate: 8, requires: ['ele_choice'] }),

  passive('enh_ancestral_weapons', 'spec', 'enhancement', 3, { stats: { ap: 8 } }, 'x', 'Ancestral Weapons', 'Increases attack power by 8 per rank.', 0, 0),
  passive('enh_shield_spec', 'spec', 'enhancement', 3, { stats: { armorPct: 0.04, dodge: 0.005 } }, '#', 'Shield Specialization', 'Increases armor and dodge per rank.', 0, 2),
  passive('enh_imp_rockbiter', 'spec', 'enhancement', 2, { ability: [{ ability: 'rockbiter_weapon', dmgPct: 0.20 }] }, 'x', 'Improved Rockbiter', 'Increases Rockbiter Weapon damage by 20% per rank.', 1, 0, { pointsGate: 2, requires: ['enh_ancestral_weapons'] }),
  passive('enh_flurry', 'spec', 'enhancement', 2, { stats: { crit: 0.02 } }, '>', 'Flurry', 'Increases critical strike chance by 2% per rank.', 1, 2, { pointsGate: 2 }),
  choice('enh_choice', 'spec', 'enhancement', '@', 'Storm Path', 'Choose one Enhancement refinement.', 2, 1, [
    { id: 'enh_choice_stormstrike', name: 'Stormstrike', icon: 'x', description: 'Stormstrike deals 25% more damage.', effect: { ability: [{ ability: 'stormstrike', dmgPct: 0.25 }] } },
    { id: 'enh_choice_toughness', name: 'Toughness', icon: '#', description: 'Increases armor and stamina.', effect: { stats: { armorPct: 0.12, sta: 4 } } },
    { id: 'enh_choice_weapon', name: 'Weapon Mastery', icon: 'x', description: 'Increases melee damage by 10%.', effect: { global: { meleeDmgPct: 0.10 } } },
  ], { pointsGate: 5 }),
  passive('enh_spirit_weapons', 'spec', 'enhancement', 2, { ability: [{ ability: 'stormstrike', cooldownPct: -0.12, costPct: -0.08 }], global: { meleeDmgPct: 0.04 } }, 'x', 'Spirit Weapons', 'Improves Stormstrike and melee damage per rank.', 3, 1, { pointsGate: 8, requires: ['enh_choice'] }),

  passive('rest_tidal_focus', 'spec', 'restoration', 3, { ability: [{ ability: 'healing_wave', costPct: -0.06 }] }, 'v', 'Tidal Focus', 'Reduces Healing Wave cost by 6% per rank.', 0, 0),
  passive('rest_imp_healing_wave', 'spec', 'restoration', 3, { ability: [{ ability: 'healing_wave', castPct: -0.05, dmgPct: 0.05 }] }, '+', 'Improved Healing Wave', 'Makes Healing Wave faster and stronger per rank.', 0, 2),
  passive('rest_ancestral_healing', 'spec', 'restoration', 2, { stats: { armorPct: 0.05 }, global: { healPct: 0.03 } }, '#', 'Ancestral Healing', 'Increases armor and healing per rank.', 1, 0, { pointsGate: 2, requires: ['rest_tidal_focus'] }),
  passive('rest_healing_grace', 'spec', 'restoration', 2, { global: { healPct: 0.04 }, stats: { spi: 2 } }, '+', 'Healing Grace', 'Increases healing and Spirit per rank.', 1, 2, { pointsGate: 2 }),
  choice('rest_choice', 'spec', 'restoration', '@', 'Nature Blessing', 'Choose one Restoration refinement.', 2, 1, [
    { id: 'rest_choice_swiftness', name: 'Nature Swiftness', icon: '>', description: 'Healing Wave casts 25% faster.', effect: { ability: [{ ability: 'healing_wave', castPct: -0.25 }] } },
    { id: 'rest_choice_mana', name: 'Mana Tide', icon: 'v', description: 'Healing Wave costs 18% less.', effect: { ability: [{ ability: 'healing_wave', costPct: -0.18 }] } },
    { id: 'rest_choice_purification', name: 'Purification', icon: '+', description: 'Increases healing by 10%.', effect: { global: { healPct: 0.10 } } },
  ], { pointsGate: 5 }),
  passive('rest_chain_focus', 'spec', 'restoration', 2, { global: { healPct: 0.07 }, stats: { int: 2 } }, '+', 'Ancestral Guidance', 'Increases healing and Intellect per rank.', 3, 1, { pointsGate: 8, requires: ['rest_choice'] }),
]

const DRUID_CLASS: TalentNode[] = [
  passive('dru_natures_grasp', 'class', undefined, 3, { ability: [{ ability: 'entangling_roots', costPct: -0.06 }], stats: { spi: 1 } }, 'v', 'Nature Grasp', 'Reduces Entangling Roots cost and increases Spirit per rank.', 0, 0),
  passive('dru_feral_aggression', 'class', undefined, 3, { ability: [{ ability: 'maul', dmgPct: 0.05 }, { ability: 'claw', dmgPct: 0.05 }] }, 'x', 'Feral Aggression', 'Increases Maul and Claw damage by 5% per rank.', 0, 2),
  passive('dru_imp_mark', 'class', undefined, 2, { ability: [{ ability: 'mark_of_the_wild', dmgPct: 0.20 }], stats: { armorPct: 0.03 } }, '+', 'Improved Mark of the Wild', 'Strengthens Mark of the Wild and armor per rank.', 1, 0, { requires: ['dru_natures_grasp'] }),
  passive('dru_naturalist', 'class', undefined, 2, { ability: [{ ability: 'healing_touch', castPct: -0.08 }, { ability: 'wrath', castPct: -0.04 }] }, '>', 'Naturalist', 'Makes Healing Touch and Wrath faster per rank.', 1, 1, { pointsGate: 2 }),
  passive('dru_thick_hide', 'class', undefined, 3, { stats: { armorPct: 0.04 } }, '#', 'Thick Hide', 'Increases armor by 4% per rank.', 1, 2, { requires: ['dru_feral_aggression'] }),
  choice('dru_natures_path', 'class', undefined, '@', 'Nature Path', 'Choose one druid emphasis.', 2, 1, [
    { id: 'dru_path_balance', name: 'Moonglow', icon: '*', description: 'Increases spell damage by 8%.', effect: { global: { spellDmgPct: 0.08 } } },
    { id: 'dru_path_feral', name: 'Heart of the Wild', icon: 'x', description: 'Increases Stamina and attack power.', effect: { stats: { staPct: 0.08, apPct: 0.08 } } },
    { id: 'dru_path_resto', name: 'Gift of Nature', icon: '+', description: 'Increases healing by 8%.', effect: { global: { healPct: 0.08 } } },
  ], { pointsGate: 5 }),
  active('dru_barkskin', 'class', undefined, { grant: { ability: 'barkskin' } }, '#', 'Barkskin', 'Grants early access to Barkskin.', 3, 0, { pointsGate: 8, requires: ['dru_imp_mark'] }),
  passive('dru_furor', 'class', undefined, 2, { stats: { int: 3, sta: 3 } }, '+', 'Furor', 'Increases Intellect and Stamina by 3 per rank.', 3, 2, { pointsGate: 8, requires: ['dru_natures_path'] }),
]

const DRUID_SPECS: SpecDef[] = [
  spec('balance', 'druid', 'Balance', 'dps', '*', 'A caster who uses lunar and nature magic from range.', 'starfire', 'Moonfury', 'Increases spell damage and Intellect.', { global: { spellDmgPct: 0.10 }, stats: { int: 4 } }),
  spec('feral', 'druid', 'Feral', 'tank', 'x', 'A shapeshifter who tanks in bear form and fights up close.', 'bear_form', 'Heart of the Wild', 'Increases threat, armor, and attack power.', { global: { threatPct: 0.20, meleeDmgPct: 0.06 }, stats: { armorPct: 0.08 } }),
  spec('restoration', 'druid', 'Restoration', 'healer', '+', 'A healer using heal-over-time effects and efficient nature magic.', 'regrowth', 'Gift of Nature', 'Increases healing done by 14%.', { global: { healPct: 0.14 } }),
]

const DRUID_SPEC_NODES: TalentNode[] = [
  passive('bal_imp_wrath', 'spec', 'balance', 3, { ability: [{ ability: 'wrath', castPct: -0.04, dmgPct: 0.05 }] }, '*', 'Improved Wrath', 'Makes Wrath faster and stronger per rank.', 0, 0),
  passive('bal_imp_moonfire', 'spec', 'balance', 3, { ability: [{ ability: 'moonfire', dmgPct: 0.08 }] }, '*', 'Improved Moonfire', 'Increases Moonfire damage by 8% per rank.', 0, 2),
  passive('bal_natures_reach', 'spec', 'balance', 2, { ability: [{ ability: 'entangling_roots', castPct: -0.12 }, { ability: 'starfire', castPct: -0.08 }] }, '>', 'Nature Reach', 'Improves root and Starfire cast flow per rank.', 1, 0, { pointsGate: 2, requires: ['bal_imp_wrath'] }),
  passive('bal_vengeance', 'spec', 'balance', 2, { stats: { crit: 0.02 } }, 'x', 'Vengeance', 'Increases critical strike chance by 2% per rank.', 1, 2, { pointsGate: 2 }),
  choice('bal_choice', 'spec', 'balance', '@', 'Moonkin Path', 'Choose one Balance refinement.', 2, 1, [
    { id: 'bal_choice_moonkin', name: 'Moonkin Form', icon: '#', description: 'Increases armor and spell damage.', effect: { stats: { armorPct: 0.14 }, global: { spellDmgPct: 0.06 } } },
    { id: 'bal_choice_grace', name: 'Nature Grace', icon: '>', description: 'Wrath and Starfire cast 15% faster.', effect: { ability: [{ ability: 'wrath', castPct: -0.15 }, { ability: 'starfire', castPct: -0.15 }] } },
    { id: 'bal_choice_moonglow', name: 'Moonglow', icon: 'v', description: 'Balance spells cost 15% less.', effect: { ability: [{ ability: 'wrath', costPct: -0.15 }, { ability: 'moonfire', costPct: -0.15 }, { ability: 'starfire', costPct: -0.15 }] } },
  ], { pointsGate: 5 }),
  passive('bal_starfire_mastery', 'spec', 'balance', 2, { ability: [{ ability: 'starfire', dmgPct: 0.12, castPct: -0.08 }] }, '*', 'Starfire Mastery', 'Improves Starfire damage and cast speed per rank.', 3, 1, { pointsGate: 8, requires: ['bal_choice'] }),

  passive('feral_thick_hide', 'spec', 'feral', 3, { stats: { armorPct: 0.05 } }, '#', 'Thick Hide', 'Increases armor by 5% per rank.', 0, 0),
  passive('feral_ferocity', 'spec', 'feral', 3, { ability: [{ ability: 'maul', costPct: -0.06 }, { ability: 'claw', costPct: -0.06 }] }, 'v', 'Ferocity', 'Reduces Maul and Claw cost by 6% per rank.', 0, 2),
  passive('feral_brutal_impact', 'spec', 'feral', 2, { ability: [{ ability: 'maul', dmgPct: 0.10 }, { ability: 'swipe', dmgPct: 0.10 }] }, 'x', 'Brutal Impact', 'Increases bear attack damage per rank.', 1, 0, { pointsGate: 2, requires: ['feral_thick_hide'] }),
  passive('feral_feline_swiftness', 'spec', 'feral', 2, { stats: { dodge: 0.02, agi: 2 } }, '>', 'Feline Swiftness', 'Increases dodge and Agility per rank.', 1, 2, { pointsGate: 2 }),
  choice('feral_choice', 'spec', 'feral', '@', 'Feral Instinct', 'Choose one Feral refinement.', 2, 1, [
    { id: 'feral_choice_bear', name: 'Dire Bear', icon: '#', description: 'Increases armor and threat.', effect: { stats: { armorPct: 0.12 }, global: { threatPct: 0.10 } } },
    { id: 'feral_choice_cat', name: 'Predatory Strikes', icon: 'x', description: 'Increases melee damage by 10%.', effect: { global: { meleeDmgPct: 0.10 } } },
    { id: 'feral_choice_survival', name: 'Survival Instincts', icon: '+', description: 'Increases maximum health by 14%.', effect: { stats: { maxHpPct: 0.14 } } },
  ], { pointsGate: 5 }),
  passive('feral_heart_wild', 'spec', 'feral', 2, { stats: { staPct: 0.05, apPct: 0.05 }, global: { threatPct: 0.05 } }, 'x', 'Heart of the Wild', 'Improves stamina, attack power, and threat per rank.', 3, 1, { pointsGate: 8, requires: ['feral_choice'] }),

  passive('rest_imp_rejuv', 'spec', 'restoration', 3, { ability: [{ ability: 'rejuvenation', dmgPct: 0.08 }] }, '+', 'Improved Rejuvenation', 'Increases Rejuvenation healing by 8% per rank.', 0, 0),
  passive('rest_druid_naturalist', 'spec', 'restoration', 3, { ability: [{ ability: 'healing_touch', castPct: -0.05, dmgPct: 0.05 }] }, '+', 'Naturalist', 'Makes Healing Touch faster and stronger per rank.', 0, 2),
  passive('rest_reflection', 'spec', 'restoration', 2, { ability: [{ ability: 'healing_touch', costPct: -0.10 }, { ability: 'rejuvenation', costPct: -0.10 }] }, 'v', 'Reflection', 'Reduces core healing costs by 10% per rank.', 1, 0, { pointsGate: 2, requires: ['rest_imp_rejuv'] }),
  passive('rest_imp_regrowth', 'spec', 'restoration', 2, { ability: [{ ability: 'regrowth', dmgPct: 0.12 }] }, '+', 'Improved Regrowth', 'Increases Regrowth healing by 12% per rank.', 1, 2, { pointsGate: 2 }),
  choice('rest_druid_choice', 'spec', 'restoration', '@', 'Restoration Gift', 'Choose one Restoration refinement.', 2, 1, [
    { id: 'rest_druid_choice_swift', name: 'Nature Swiftness', icon: '>', description: 'Healing Touch casts 25% faster.', effect: { ability: [{ ability: 'healing_touch', castPct: -0.25 }] } },
    { id: 'rest_druid_choice_innervate', name: 'Innervate', icon: 'v', description: 'Healing spells cost 16% less.', effect: { ability: [{ ability: 'healing_touch', costPct: -0.16 }, { ability: 'regrowth', costPct: -0.16 }, { ability: 'rejuvenation', costPct: -0.16 }] } },
    { id: 'rest_druid_choice_living', name: 'Living Spirit', icon: '*', description: 'Increases Spirit by 10.', effect: { stats: { spi: 10 } } },
  ], { pointsGate: 5 }),
  passive('rest_tree_life', 'spec', 'restoration', 2, { global: { healPct: 0.07 }, stats: { spi: 3 } }, '+', 'Tree of Life', 'Increases healing and Spirit per rank.', 3, 1, { pointsGate: 8, requires: ['rest_druid_choice'] }),
]

const TALENTS: Record<'priest' | 'paladin' | 'shaman' | 'druid', ClassTalents> = {
  paladin: { class: 'paladin', nodes: [...PALADIN_CLASS, ...PALADIN_SPEC_NODES], specs: PALADIN_SPECS },
  priest: { class: 'priest', nodes: [...PRIEST_CLASS, ...PRIEST_SPEC_NODES], specs: PRIEST_SPECS },
  shaman: { class: 'shaman', nodes: [...SHAMAN_CLASS, ...SHAMAN_SPEC_NODES], specs: SHAMAN_SPECS },
  druid: { class: 'druid', nodes: [...DRUID_CLASS, ...DRUID_SPEC_NODES], specs: DRUID_SPECS },
}
