import type { Monster, MonsterAction } from '@/lib/compendium/types';
import { crLabel } from '@/lib/compendium';
import { abilityModifier } from '@/lib/rules';
import { formatModifier } from '@/lib/format';

function actionList(value: MonsterAction[] | string | undefined): MonsterAction[] {
  return Array.isArray(value) ? value : [];
}

/** A single "Label value" line in the Codex stat block. */
function StatLine({ label, children }: { label: string; children?: React.ReactNode }) {
  if (children === undefined || children === null || children === '' || children === false) return null;
  return (
    <p className="text-sm leading-relaxed text-ink-soft">
      <span className="font-display font-bold text-danger">{label} </span>
      {children}
    </p>
  );
}

/** Join all movement modes into a statblock Speed line, e.g. "40 ft., climb 40 ft., fly 80 ft." */
function speedLine(speed: Monster['speed']): string {
  if (!speed) return '';
  const entries = Object.entries(speed).filter(([, v]) => typeof v === 'number') as [string, number][];
  const walk = entries.find(([k]) => k === 'walk');
  const rest = entries.filter(([k]) => k !== 'walk');
  const parts = [...(walk ? [`${walk[1]} ft.`] : []), ...rest.map(([k, v]) => `${k} ${v} ft.`)];
  return parts.join(', ');
}

const SAVE_LABELS: [keyof Monster, string][] = [
  ['strength_save', 'STR'], ['dexterity_save', 'DEX'], ['constitution_save', 'CON'],
  ['intelligence_save', 'INT'], ['wisdom_save', 'WIS'], ['charisma_save', 'CHA'],
];

export function MonsterDetail({ monster: m }: { monster: Monster }) {
  const abilities: [string, number | undefined][] = [
    ['STR', m.strength],
    ['DEX', m.dexterity],
    ['CON', m.constitution],
    ['INT', m.intelligence],
    ['WIS', m.wisdom],
    ['CHA', m.charisma],
  ];
  const subtitle = [m.size, m.type, m.alignment].filter(Boolean).join(', ');

  const saves = SAVE_LABELS
    .map(([k, label]) => [label, m[k] as number | null | undefined] as const)
    .filter(([, v]) => typeof v === 'number')
    .map(([label, v]) => `${label} ${formatModifier(v as number)}`)
    .join(', ');
  const skills = m.skills
    ? Object.entries(m.skills).map(([k, v]) => `${k[0]!.toUpperCase()}${k.slice(1)} ${formatModifier(v)}`).join(', ')
    : '';

  // Passive Perception, computed from the creature's own stats so it can never
  // disagree with them (7 SRD monsters ship a wrong passive in their senses string).
  const percMod = m.skills?.perception ?? (m.wisdom !== undefined ? abilityModifier(m.wisdom) : undefined);
  const passivePerception = percMod !== undefined ? 10 + percMod : undefined;
  const senses = m.senses && passivePerception !== undefined
    ? /passive Perception\s+\d+/i.test(m.senses)
      ? m.senses.replace(/passive Perception\s+\d+/i, `passive Perception ${passivePerception}`)
      : `${m.senses}, passive Perception ${passivePerception}`
    : m.senses;
  return (
    <div className="font-display">
      <header>
        <h2 className="font-display text-3xl font-semibold tracking-tight text-danger">{m.name}</h2>
        {subtitle && <p className="text-sm italic text-muted">{subtitle}</p>}
      </header>

      <hr className="gilt-rule my-4" />

      <div className="space-y-1">
        <StatLine label="Armor Class">{m.armor_class ?? '—'}{m.armor_desc ? ` (${m.armor_desc})` : ''}</StatLine>
        <StatLine label="Hit Points">{m.hit_points ?? '—'}{m.hit_dice ? ` (${m.hit_dice})` : ''}</StatLine>
        <StatLine label="Speed">{speedLine(m.speed) || null}</StatLine>
      </div>

      <hr className="gilt-rule my-4" />

      <div className="grid grid-cols-6 gap-2">
        {abilities.map(([label, score]) => (
          <div key={label} className="flex flex-col items-center gap-0.5 rounded-xl border border-line bg-surface-2 px-1 py-2 text-center">
            <span className="smallcaps text-danger" style={{ fontSize: 9 }}>{label}</span>
            <span className="font-display text-lg font-semibold text-ink">{score ?? '—'}</span>
            <span className="font-mono text-xs text-muted">
              {score !== undefined ? formatModifier(abilityModifier(score)) : ''}
            </span>
          </div>
        ))}
      </div>

      {(saves || skills || m.damage_resistances || m.damage_immunities || m.condition_immunities || senses || m.languages) && (
        <>
          <hr className="gilt-rule my-4" />
          <div className="space-y-1">
            <StatLine label="Saving Throws">{saves || null}</StatLine>
            <StatLine label="Skills">{skills || null}</StatLine>
            <StatLine label="Vulnerabilities">{m.damage_vulnerabilities}</StatLine>
            <StatLine label="Resistances">{m.damage_resistances}</StatLine>
            <StatLine label="Immunities">{m.damage_immunities}</StatLine>
            <StatLine label="Condition Immunities">{m.condition_immunities}</StatLine>
            <StatLine label="Senses">{senses}</StatLine>
            <StatLine label="Languages">{m.languages}</StatLine>
          </div>
        </>
      )}

      <hr className="gilt-rule my-4" />
      <StatLine label="Challenge">{crLabel(m)}</StatLine>

      <ActionBlock title="Special Abilities" actions={actionList(m.special_abilities)} />
      <ActionBlock title="Actions" actions={actionList(m.actions)} />
      <ActionBlock title="Reactions" actions={actionList(m.reactions)} />
      <ActionBlock title="Legendary Actions" actions={actionList(m.legendary_actions)} />
    </div>
  );
}

function ActionBlock({ title, actions }: { title: string; actions: MonsterAction[] }) {
  if (actions.length === 0) return null;
  return (
    <section className="mt-5">
      <h3 className="mb-2 border-b-2 border-danger pb-1 font-display text-lg font-semibold text-danger">{title}</h3>
      <div className="space-y-2">
        {actions.map((a, i) => (
          <p key={`${a.name}-${i}`} className="text-sm leading-relaxed text-ink-soft">
            <strong className="italic text-ink">{a.name}.</strong> {a.desc}
          </p>
        ))}
      </div>
    </section>
  );
}
