import type { PartyMember, Spell } from '../game'
import type { Ability } from '../profile'
import { createStackCounts, stackCount } from './stackCounts'

export const DEFAULT_TICK_MS = 700

export function clamp(value: number, min: number, max: number) {
  return Math.min(max, Math.max(min, value))
}

export function chooseRandom<T>(items: T[], count: number) {
  const pool = [...items]
  const result: T[] = []
  while (pool.length > 0 && result.length < count) {
    const index = Math.floor(Math.random() * pool.length)
    result.push(pool.splice(index, 1)[0])
  }
  return result
}

export function effectiveMaxHealth(member: PartyMember) {
  return Math.max(
    1,
    Math.round(member.maxHealth * (member.maxHealthPenaltyTicks && member.maxHealthPenaltyTicks > 0 ? 0.75 : 1)),
  )
}

export function healAmount(member: PartyMember, amount: number, multiplier = 1) {
  return Math.round(amount * (member.healingReductionTicks && member.healingReductionTicks > 0 ? 0.75 : 1) * multiplier)
}

export function healMember(member: PartyMember, amount: number, multiplier = 1) {
  return clamp(member.health + healAmount(member, amount, multiplier), 0, effectiveMaxHealth(member))
}

export function memberHotEffects(member: PartyMember) {
  if (member.hotEffects?.length) return member.hotEffects
  return member.hotTicks > 0
    ? [{ id: 'legacy-renew', spellId: 'legacy-renew', label: 'Renew', ticks: member.hotTicks, power: 6 }]
    : []
}

export function effectId(prefix: string) {
  return `${prefix}-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`}`
}

export function addHotEffect(member: PartyMember, spell: Spell, ticks = 5) {
  const nextEffect = {
    id: effectId(spell.id),
    spellId: spell.id,
    label: spell.name,
    ticks,
    power: Math.max(1, Math.round(spell.power / 2)),
  }
  const currentEffects = memberHotEffects(member).filter((effect) => effect.spellId !== spell.id)
  return [...currentEffects, nextEffect]
}

export function addBounceHeal(member: PartyMember, spell: Spell) {
  return [
    ...(member.bounceHeals ?? []),
    {
      id: effectId(spell.id),
      label: spell.name,
      charges: 4,
      power: spell.power,
    },
  ]
}

export function tickHotEffects(effects: PartyMember['hotEffects']) {
  return (effects ?? [])
    .map((effect) => ({ ...effect, ticks: effect.ticks - 1 }))
    .filter((effect) => effect.ticks > 0)
}

export function formatEffectTime(ticks: number, tickMs = DEFAULT_TICK_MS) {
  const seconds = (ticks * tickMs) / 1000
  return Number.isInteger(seconds) ? `${seconds}s` : `${seconds.toFixed(1)}s`
}

export function buffStacks<T extends string>(items: readonly T[], id: T) {
  return stackCount(createStackCounts(items), id)
}

export function createLogEntry(nextLogId: { current: number }, text: string, tone: 'system' | 'heal' | 'danger' | 'loot') {
  return { id: nextLogId.current++, text, tone }
}

export function toCombatSpell(ability: Ability, key: string, healingPower = 0): Spell {
  const kinds: Record<string, Spell['kind']> = {
    direct_heal: 'direct',
    direct_hot: 'direct',
    heal_over_time: 'hot',
    party_heal: 'group',
    party_hot: 'group',
    party_absorb: 'group',
    absorb: 'shield',
    damage_reduction: 'damage_reduction',
    bounce_heal: 'bounce_heal',
    cleanse: 'cleanse',
  }
  return {
    id: String(ability.id),
    key,
    name: ability.name,
    description: ability.description,
    cost: ability.cost,
    cooldown: ability.cooldown,
    power: ability.power + healingPower,
    glyph: ability.glyph,
    kind: kinds[ability.spellType] ?? 'direct',
    effectType: ability.spellType,
  }
}

export function resetParty(partyTemplate: PartyMember[]) {
  return partyTemplate.map((member) => ({
    ...member,
    health: member.maxHealth,
    shield: 0,
    hotTicks: 0,
    hotEffects: undefined,
    debuff: undefined,
    debuffTicks: undefined,
    poisonStacks: undefined,
    maxHealthPenaltyTicks: undefined,
    healingReductionTicks: undefined,
    damageReductionTicks: undefined,
    bounceHeals: undefined,
  }))
}
