import type { ToolUseContext } from '../../Tool.js'
import type {
  LocalJSXCommandContext,
  LocalJSXCommandOnDone,
} from '../../types/command.js'
import { getGlobalConfig, saveGlobalConfig } from '../../utils/config.js'
import { getCompanion, roll, rollWithSeed } from '../../buddy/companion.js'
import { renderSprite, renderFace } from '../../buddy/sprites.js'
import { RARITY_STARS, SPECIES } from '../../buddy/types.js'

// Fair reroll: pick a random seed whose species has the fewest rolls.
// Once all species reach the same count, the pool resets effectively.
function fairRoll(): { seed: string; species: string } {
  const config = getGlobalConfig()
  const counts: Record<string, number> = { ...config.companionRollCounts }

  // Find the minimum roll count
  const minCount = Math.min(...SPECIES.map(s => counts[s] ?? 0))

  // Candidates: species at the minimum count
  const candidates = SPECIES.filter(s => (counts[s] ?? 0) === minCount)

  // Pick a random candidate
  const target = candidates[Math.floor(Math.random() * candidates.length)]!

  // Generate random seeds until we hit the target species
  let seed: string
  let result: ReturnType<typeof rollWithSeed>
  let attempts = 0
  do {
    seed = `reroll-${Date.now()}-${Math.random().toString(36).slice(2)}-${attempts}`
    result = rollWithSeed(seed)
    attempts++
  } while (result.bones.species !== target && attempts < 500)

  return { seed, species: result.bones.species }
}

function renderCard(): string {
  const companion = getCompanion()
  if (!companion) return 'No companion hatched yet. Run /buddy to hatch one!'

  const sprite = renderSprite(companion)
  const face = renderFace(companion)
  const stars = RARITY_STARS[companion.rarity]
  const shinyTag = companion.shiny ? ' ✨ SHINY' : ''
  const statsLines = Object.entries(companion.stats)
    .map(([k, v]) => {
      const bar = '█'.repeat(Math.round(v / 5)) + '░'.repeat(20 - Math.round(v / 5))
      return `  ${k.padEnd(10)} ${bar} ${v}`
    })
    .join('\n')

  // Show collection progress
  const config = getGlobalConfig()
  const counts = config.companionRollCounts ?? {}
  const seen = SPECIES.filter(s => (counts[s] ?? 0) > 0).length
  const total = SPECIES.length

  return [
    `┌─── ${companion.name} ───┐`,
    `  Species: ${companion.species}  ${stars}${shinyTag}`,
    `  Rarity:  ${companion.rarity}`,
    `  Hat:     ${companion.hat}`,
    `  Eyes:    ${companion.eye}`,
    `  Face:    ${face}`,
    '',
    ...sprite.map(l => `  ${l}`),
    '',
    '  Stats:',
    statsLines,
    '',
    `  Personality: ${companion.personality}`,
    `  Hatched: ${new Date(companion.hatchedAt).toLocaleDateString()}`,
    `  Collection: ${seen}/${total} species discovered`,
    `└${'─'.repeat(companion.name.length + 6)}┘`,
  ].join('\n')
}

function hatchWithSeed(seed: string) {
  const { bones } = rollWithSeed(seed)
  const name = `Buddy_${bones.species}`
  const soul = {
    name,
    personality: `A cheerful ${bones.species} companion with a knack for ${bones.rarity === 'legendary' ? 'legendary wisdom' : 'coding adventures'}.`,
    hatchedAt: Date.now(),
  }

  // Update config: save companion, seed, and bump roll count
  saveGlobalConfig(cfg => {
    const counts = { ...cfg.companionRollCounts }
    counts[bones.species] = (counts[bones.species] ?? 0) + 1
    return { ...cfg, companion: soul, companionSeed: seed, companionRollCounts: counts }
  })

  return { ...soul, ...bones }
}

export async function call(
  onDone: LocalJSXCommandOnDone,
  context: ToolUseContext & LocalJSXCommandContext,
  args: string,
): Promise<null> {
  const sub = args.trim().toLowerCase()

  // No companion yet — hatch one
  if (!sub || sub === 'hatch') {
    const config = getGlobalConfig()
    if (config.companion) {
      onDone(renderCard(), { display: 'system' })
      return null
    }
    const { seed } = fairRoll()
    const companion = hatchWithSeed(seed)
    const sprite = renderSprite(companion)
    const stars = RARITY_STARS[companion.rarity]
    const shinyTag = companion.shiny ? ' ✨ SHINY!' : ''
    onDone(
      [
        '🥚 *crack* ...',
        '',
        ...sprite.map(l => `  ${l}`),
        '',
        `  A ${companion.rarity} ${companion.species} appeared! ${stars}${shinyTag}`,
        `  Name: ${companion.name}`,
        '',
        '  Use /buddy card to see full stats.',
        '  Use /buddy rename <name> to rename.',
        '  Use /buddy pet to show some love!',
      ].join('\n'),
      { display: 'system' },
    )
    return null
  }

  if (sub === 'card' || sub === 'stats') {
    onDone(renderCard(), { display: 'system' })
    return null
  }

  if (sub === 'pet') {
    const companion = getCompanion()
    if (!companion) {
      onDone('No companion to pet! Use /buddy to hatch one.', { display: 'system' })
      return null
    }
    context.setAppState(prev => ({ ...prev, companionPetAt: Date.now() }))
    onDone(`You pet ${companion.name}! 💕`, { display: 'system' })
    return null
  }

  if (sub === 'mute') {
    const config = getGlobalConfig()
    const newMuted = !config.companionMuted
    saveGlobalConfig(cfg => ({ ...cfg, companionMuted: newMuted }))
    onDone(
      newMuted
        ? 'Companion muted. Use /buddy mute to unmute.'
        : 'Companion unmuted!',
      { display: 'system' },
    )
    return null
  }

  if (sub.startsWith('rename ')) {
    const newName = args.trim().slice('rename '.length).trim()
    if (!newName) {
      onDone('Usage: /buddy rename <new name>', { display: 'system' })
      return null
    }
    const config = getGlobalConfig()
    if (!config.companion) {
      onDone('No companion to rename! Use /buddy to hatch one.', { display: 'system' })
      return null
    }
    saveGlobalConfig(cfg => ({
      ...cfg,
      companion: { ...cfg.companion!, name: newName },
    }))
    onDone(`Companion renamed to ${newName}!`, { display: 'system' })
    return null
  }

  if (sub === 'reroll') {
    const { seed, species } = fairRoll()
    const companion = hatchWithSeed(seed)
    const sprite = renderSprite(companion)
    const stars = RARITY_STARS[companion.rarity]
    const shinyTag = companion.shiny ? ' ✨ SHINY!' : ''
    const config = getGlobalConfig()
    const counts = config.companionRollCounts ?? {}
    const seen = SPECIES.filter(s => (counts[s] ?? 0) > 0).length
    onDone(
      [
        '🔄 Rerolling...',
        '',
        ...sprite.map(l => `  ${l}`),
        '',
        `  A ${companion.rarity} ${companion.species} appeared! ${stars}${shinyTag}`,
        `  Name: ${companion.name}`,
        `  Collection: ${seen}/${SPECIES.length} species discovered`,
      ].join('\n'),
      { display: 'system' },
    )
    return null
  }

  onDone(
    [
      'Usage: /buddy [subcommand]',
      '',
      '  /buddy          — Hatch or view your companion',
      '  /buddy card     — Show companion card with stats',
      '  /buddy pet      — Pet your companion 💕',
      '  /buddy mute     — Toggle companion speech bubbles',
      '  /buddy rename   — Rename your companion',
      '  /buddy reroll   — Release and re-hatch (fair rotation)',
    ].join('\n'),
    { display: 'system' },
  )
  return null
}
