import type { EnemyKind } from './actionCombatSimulation'

export type ActionAttackKind =
  | 'tankMelee'
  | 'charge'
  | 'groundSlam'
  | 'fireballVolley'
  | 'birdDive'
  | 'spinningBlade'
  | 'circularCharge'
  | 'bodyContact'

export type ActionAiAvoidanceSource =
  | 'projectile'
  | 'persistentArea'
  | 'circleTelegraph'
  | 'lineTelegraph'

export type ActionAiAvoidanceConfig = {
  enabled: boolean
  buffer: number
  moveSpeed: number
  avoidDistance: number
  lineWidthMultiplier?: number
}

export type ActionAttackConfig = {
  id: string
  label: string
  kind: ActionAttackKind
  enabled: boolean
  frequencySeconds: number
  damage: number
  windupSeconds?: number
  recoverSeconds?: number
  speed?: number
  radius?: number
  durationSeconds?: number
  everyNthCharge?: number
  aiAvoidance?: Partial<Record<ActionAiAvoidanceSource, ActionAiAvoidanceConfig>>
}

export type ActionEnemyMechanicConfig = {
  kind: EnemyKind
  label: string
  role: 'boss' | 'mob'
  attacks: ActionAttackConfig[]
}

export type ActionMechanicConfig = Record<EnemyKind, ActionEnemyMechanicConfig>

export const ACTION_MECHANIC_CONFIG_KEY = 'i-want-to-heal:action-mode-mechanics:v2'

export const DEFAULT_ACTION_MECHANIC_CONFIG: ActionMechanicConfig = {
  bulldrome: {
    kind: 'bulldrome',
    label: 'Bulldrome',
    role: 'boss',
    attacks: [
      createAttack('bulldrome-tank-melee', 'Tank Melee', 'tankMelee', 0.9, 42),
      createAttack('bulldrome-charge', 'Charge', 'charge', 2.8, 92, {
        windupSeconds: 0.82,
        recoverSeconds: 0.86,
        speed: 650,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.42 }),
        },
      }),
      createAttack('bulldrome-ground-slam', 'Ground Slam', 'groundSlam', 3, 110, {
        windupSeconds: 1.25,
        radius: 142,
        everyNthCharge: 3,
        aiAvoidance: {
          circleTelegraph: createAiAvoidance({ buffer: 12 }),
        },
      }),
      createAttack('bulldrome-body-contact', 'Body Contact', 'bodyContact', 0, 38),
    ],
  },
  bullfango: {
    kind: 'bullfango',
    label: 'Bullfango',
    role: 'mob',
    attacks: [
      createAttack('bullfango-tank-melee', 'Tank Melee', 'tankMelee', 1.35, 22),
      createAttack('bullfango-charge', 'Charge', 'charge', 1.6, 46, {
        windupSeconds: 0.68,
        recoverSeconds: 1.05,
        speed: 510,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.42 }),
        },
      }),
      createAttack('bullfango-body-contact', 'Body Contact', 'bodyContact', 0, 18),
    ],
  },
  'yian-kut-ku': {
    kind: 'yian-kut-ku',
    label: 'Yian Kut-Ku',
    role: 'boss',
    attacks: [
      createAttack('yian-tank-melee', 'Tank Peck', 'tankMelee', 1, 38),
      createAttack('yian-fireballs', 'Fireball Volley', 'fireballVolley', 2.4, 70, {
        windupSeconds: 1,
        recoverSeconds: 1.1,
        speed: 190,
        aiAvoidance: {
          projectile: createAiAvoidance({ buffer: 34 }),
          persistentArea: createAiAvoidance({ buffer: 18 }),
        },
      }),
      createAttack('yian-body-contact', 'Body Contact', 'bodyContact', 0, 32),
    ],
  },
  bird: {
    kind: 'bird',
    label: 'Bird',
    role: 'mob',
    attacks: [
      createAttack('bird-tank-melee', 'Tank Claw', 'tankMelee', 1.15, 18),
      createAttack('bird-dive', 'Dive Flight', 'birdDive', 3.2, 42, {
        speed: 340,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.42 }),
        },
      }),
      createAttack('bird-body-contact', 'Body Contact', 'bodyContact', 0, 16),
    ],
  },
  'cyber-dragon': {
    kind: 'cyber-dragon',
    label: 'Cyber Dragon',
    role: 'boss',
    attacks: [
      createAttack('cyber-tank-melee', 'Tank Slash', 'tankMelee', 1, 44),
      createAttack('cyber-spinning-blade', 'Spinning Blade', 'spinningBlade', 10, 22, {
        recoverSeconds: 15,
        speed: 96,
        radius: 24,
        aiAvoidance: {
          persistentArea: createAiAvoidance({ avoidDistance: 150, buffer: 42, moveSpeed: 184 }),
        },
      }),
      createAttack('cyber-circular-charge', 'Circular Charge', 'circularCharge', 6.8, 84, {
        windupSeconds: 1.35,
        recoverSeconds: 0.8,
        speed: 520,
        radius: 62,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.48 }),
        },
      }),
      createAttack('cyber-body-contact', 'Body Contact', 'bodyContact', 0, 34),
    ],
  },
  'claudecraft-mob': {
    kind: 'claudecraft-mob',
    label: 'ClaudeCraft Dungeon Mob',
    role: 'mob',
    attacks: [
      createAttack('cc-mob-tank-melee', 'Tank Melee', 'tankMelee', 2.1, 9),
      createAttack('cc-mob-lunge', 'Lunge', 'charge', 2.6, 12, {
        windupSeconds: 0.62,
        recoverSeconds: 0.8,
        speed: 430,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.38 }),
        },
      }),
      createAttack('cc-mob-body-contact', 'Body Contact', 'bodyContact', 0, 5),
    ],
  },
  'morthen-the-gravecaller': {
    kind: 'morthen-the-gravecaller',
    label: 'Morthen the Gravecaller',
    role: 'boss',
    attacks: [
      createAttack('morthen-tank-melee', 'Grave Strike', 'tankMelee', 2.6, 18),
      createAttack('morthen-charge', 'Grave Lunge', 'charge', 3.1, 22, {
        windupSeconds: 0.78,
        recoverSeconds: 0.9,
        speed: 460,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.42 }),
        },
      }),
      createAttack('morthen-shadow-pulse', 'Shadow Pulse', 'groundSlam', 2, 22, {
        windupSeconds: 1.1,
        radius: 132,
        everyNthCharge: 2,
        aiAvoidance: {
          circleTelegraph: createAiAvoidance({ buffer: 12 }),
        },
      }),
      createAttack('morthen-body-contact', 'Body Contact', 'bodyContact', 0, 8),
    ],
  },
  'vael-the-mistcaller': {
    kind: 'vael-the-mistcaller',
    label: 'Vael the Mistcaller',
    role: 'boss',
    attacks: [
      createAttack('vael-tank-melee', 'Mist Slash', 'tankMelee', 2.4, 20),
      createAttack('vael-charge', 'Tide Rush', 'charge', 3, 24, {
        windupSeconds: 0.82,
        recoverSeconds: 0.95,
        speed: 470,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.42 }),
        },
      }),
      createAttack('vael-mist-surge', 'Mist Surge', 'groundSlam', 2, 26, {
        windupSeconds: 1.05,
        radius: 148,
        everyNthCharge: 2,
        aiAvoidance: {
          circleTelegraph: createAiAvoidance({ buffer: 14 }),
        },
      }),
      createAttack('vael-body-contact', 'Body Contact', 'bodyContact', 0, 8),
    ],
  },
  'korzul-the-gravewyrm': {
    kind: 'korzul-the-gravewyrm',
    label: 'Korzul the Gravewyrm',
    role: 'boss',
    attacks: [
      createAttack('korzul-tank-melee', 'Wyrm Bite', 'tankMelee', 2.6, 26),
      createAttack('korzul-charge', 'Gravewyrm Charge', 'charge', 3.2, 30, {
        windupSeconds: 0.95,
        recoverSeconds: 1,
        speed: 500,
        aiAvoidance: {
          lineTelegraph: createAiAvoidance({ buffer: 0, lineWidthMultiplier: 0.5 }),
        },
      }),
      createAttack('korzul-necrotic-shockwave', 'Necrotic Shockwave', 'groundSlam', 2, 36, {
        windupSeconds: 1.2,
        radius: 168,
        everyNthCharge: 2,
        aiAvoidance: {
          circleTelegraph: createAiAvoidance({ buffer: 16 }),
        },
      }),
      createAttack('korzul-body-contact', 'Body Contact', 'bodyContact', 0, 10),
    ],
  },
}

export function loadActionMechanicConfig(): ActionMechanicConfig {
  if (typeof window === 'undefined') return cloneConfig(DEFAULT_ACTION_MECHANIC_CONFIG)

  const saved = window.localStorage.getItem(ACTION_MECHANIC_CONFIG_KEY)
  if (!saved) return cloneConfig(DEFAULT_ACTION_MECHANIC_CONFIG)

  try {
    return mergeMechanicConfig(JSON.parse(saved) as Partial<ActionMechanicConfig>)
  } catch {
    return cloneConfig(DEFAULT_ACTION_MECHANIC_CONFIG)
  }
}

export function saveActionMechanicConfig(config: ActionMechanicConfig) {
  if (typeof window === 'undefined') return
  window.localStorage.setItem(ACTION_MECHANIC_CONFIG_KEY, JSON.stringify(config))
}

export function resetActionMechanicConfig() {
  const config = cloneConfig(DEFAULT_ACTION_MECHANIC_CONFIG)
  saveActionMechanicConfig(config)
  return config
}

export function getActionEnemyMechanic(kind: EnemyKind) {
  return loadActionMechanicConfig()[kind]
}

export function getActionAttack(kind: EnemyKind, attackKind: ActionAttackKind) {
  return getActionEnemyMechanic(kind).attacks.find((attack) => attack.kind === attackKind)
}

export function getEnabledActionAttack(kind: EnemyKind, attackKind: ActionAttackKind) {
  const attack = getActionAttack(kind, attackKind)
  return attack?.enabled ? attack : null
}

export function getActionAiAvoidance(
  kind: EnemyKind,
  attackKind: ActionAttackKind,
  source: ActionAiAvoidanceSource,
) {
  const attack = getEnabledActionAttack(kind, attackKind)
  const avoidance = attack?.aiAvoidance?.[source]
  return avoidance?.enabled ? avoidance : null
}

function createAttack(
  id: string,
  label: string,
  kind: ActionAttackKind,
  frequencySeconds: number,
  damage: number,
  options: Partial<Omit<ActionAttackConfig, 'id' | 'label' | 'kind' | 'enabled' | 'frequencySeconds' | 'damage'>> = {},
): ActionAttackConfig {
  return {
    id,
    label,
    kind,
    enabled: true,
    frequencySeconds,
    damage,
    ...options,
  }
}

function createAiAvoidance(options: Partial<ActionAiAvoidanceConfig> = {}): ActionAiAvoidanceConfig {
  return {
    enabled: true,
    avoidDistance: 132,
    buffer: 0,
    moveSpeed: 190,
    ...options,
  }
}

function mergeMechanicConfig(saved: Partial<ActionMechanicConfig>) {
  const merged = cloneConfig(DEFAULT_ACTION_MECHANIC_CONFIG)
  for (const kind of Object.keys(merged) as EnemyKind[]) {
    const savedEnemy = saved[kind]
    if (!savedEnemy) continue
    const savedAttacks = Array.isArray(savedEnemy.attacks) ? savedEnemy.attacks : []
    merged[kind] = {
      ...merged[kind],
      ...savedEnemy,
      kind,
      attacks: merged[kind].attacks.map((attack) => {
        const savedAttack = savedAttacks.find((candidate) => candidate.id === attack.id)
        return {
          ...attack,
          ...savedAttack,
          aiAvoidance: mergeAiAvoidance(attack.aiAvoidance, savedAttack?.aiAvoidance),
        }
      }),
    }
  }
  return merged
}

function mergeAiAvoidance(
  defaults: ActionAttackConfig['aiAvoidance'],
  saved: ActionAttackConfig['aiAvoidance'],
) {
  if (!defaults && !saved) return undefined
  const sources = new Set([
    ...Object.keys(defaults ?? {}),
    ...Object.keys(saved ?? {}),
  ] as ActionAiAvoidanceSource[])
  const merged: ActionAttackConfig['aiAvoidance'] = {}
  for (const source of sources) {
    merged[source] = {
      ...defaults?.[source],
      ...saved?.[source],
    } as ActionAiAvoidanceConfig
  }
  return merged
}

function cloneConfig(config: ActionMechanicConfig): ActionMechanicConfig {
  return structuredClone(config)
}
