import type { DungeonEncounter } from '../profile'
import { chooseRandom } from './rules'

export function encounterThreat(encounter: DungeonEncounter) {
  return (
    encounter.maxHealth
    + encounter.damage * 18
    + encounter.tankDamage * 10
    + encounter.partyDamage * 18
  )
}

export function buildRoguelikeSegment<TMechanic extends string, TExtra extends object = object>({
  pool,
  stage,
  mechanics,
  trashCandidateCount,
  bossCandidateCount,
  healthScale,
  damageScale,
  partyDamageScale,
  idBase,
  bossDescription,
  bossName,
  fallbackBossFirst = false,
  extraFields,
}: {
  pool: DungeonEncounter[]
  stage: number
  mechanics: TMechanic[]
  trashCandidateCount: (trashCount: number) => number
  bossCandidateCount: (bossCount: number) => number
  healthScale: number
  damageScale: number
  partyDamageScale: number
  idBase: number
  bossDescription: (mechanics: TMechanic[]) => string
  bossName?: (encounter: DungeonEncounter) => string
  fallbackBossFirst?: boolean
  extraFields?: (encounter: DungeonEncounter, isBoss: boolean, mechanics: TMechanic[]) => TExtra
}) {
  const trashPool = [...pool.filter((encounter) => !encounter.isBoss)]
    .sort((left, right) => encounterThreat(left) - encounterThreat(right))
  const bossPool = [...pool.filter((encounter) => encounter.isBoss)]
    .sort((left, right) => encounterThreat(left) - encounterThreat(right))
  const selectedTrash = chooseRandom(trashPool.slice(0, trashCandidateCount(trashPool.length)), 2)
  const selectedBoss = chooseRandom(bossPool.slice(0, bossCandidateCount(bossPool.length)), 1)[0]
    ?? (fallbackBossFirst ? bossPool[0] : trashPool[0])
    ?? trashPool[0]
    ?? pool[0]
  const selectedMechanics = mechanics

  return [...selectedTrash, selectedBoss].map((encounter, index) => {
    const isBoss = index === 2
    return {
      ...encounter,
      id: idBase + stage * 10 + index,
      sequence: (stage - 1) * 3 + index + 1,
      isBoss,
      encounterType: isBoss ? 'boss' : 'trash',
      enemyName: isBoss ? (bossName?.(encounter) ?? `${encounter.enemyName} ${stage}`) : encounter.enemyName,
      description: isBoss ? bossDescription(selectedMechanics) : encounter.description,
      maxHealth: Math.round(encounter.maxHealth * healthScale),
      damage: Math.round(encounter.damage * damageScale),
      tankDamage: Math.round(encounter.tankDamage * damageScale),
      partyDamage: Math.round(encounter.partyDamage * partyDamageScale),
      lootTables: [],
      ...(extraFields?.(encounter, isBoss, selectedMechanics) ?? {} as TExtra),
    }
  })
}
