import type { CSSProperties } from "react";
import { HEALER_ABILITIES } from "../../game/healers";
import { ABILITY_CONTROLLER_BINDINGS } from "../../game/controllerBindings";
import {
  ABILITY_LOADOUT_SLOTS,
  MAX_ACTIVE_ROSTER,
  MAX_EQUIPPED_SPELLS,
  PARTY_DRAFT_WAVE_COUNT,
  PARTY_RECRUITS_PER_WAVE,
  SPELL_DRAFT_WAVE_COUNT,
  SPELL_PICKS_PER_WAVE,
  partyCompositionLabel,
  partyRolePresentation,
  rpgFocusId,
} from "../../game/rpgRoguelike";
import { DEFAULT_CONTROLLER_GLYPHS } from "../../input/controllerGlyphs";
import {
  ChallengeObjective,
  createUiContext,
  currentBoss,
  FocusButton,
  GearCard,
  GearStatComparison,
  gearComparisonLabel,
  PartyCard,
  rewardSummary,
  RoutePips,
  RunHeader,
  runAccentStyle,
  SpellCard,
  type RpgRunUiContext,
  type RpgLiveCombatUi,
  type RpgRunUiProps,
} from "./RpgRunUiShared";
import "./rpgRoguelike.css";

function TacticalParty({ context, interactive = false }: { context: RpgRunUiContext; interactive?: boolean }) {
  const { run } = context;
  return (
    <section className="rpg-tactical-section" aria-label={`Current party: ${partyCompositionLabel(run.roster)}`}>
      <header>
        <h3>Party</h3>
        <span className="rpg-party-composition"><b>{partyCompositionLabel(run.roster)}</b><small>{run.roster.filter((member) => member.hp > 0).length}/{run.roster.length} standing</small></span>
      </header>
      <div className="rpg-tactical-party-grid">
        {run.roster.map((member) => (
          <PartyCard key={member.instanceId} member={member} compact action={interactive ? (
            <FocusButton
              context={context}
              focusId={rpgFocusId.partyMember(member.instanceId)}
              command={{ type: "run-action", action: { type: "party-remove", memberId: member.instanceId } }}
              className="rpg-card-action"
              label={`Remove ${member.name}, ${partyRolePresentation(member.role).label}`}
            ><span>Remove</span></FocusButton>
          ) : undefined} />
        ))}
        {!run.roster.length && <p className="rpg-empty-copy">Drafted companions appear here.</p>}
      </div>
    </section>
  );
}

function TacticalSpellbook({ context, interactive = false }: { context: RpgRunUiContext; interactive?: boolean }) {
  const { run } = context;
  return (
    <section className="rpg-tactical-section">
      <header><h3>Spellbook</h3><span>{run.selectedSpellIds.length}/{MAX_EQUIPPED_SPELLS} slots</span></header>
      <div className="rpg-tactical-spell-grid">
        {ABILITY_LOADOUT_SLOTS.map((slotId, index) => ({ slotId, index, spellId: run.abilityLoadout[slotId] }))
          .filter((entry): entry is { slotId: typeof ABILITY_LOADOUT_SLOTS[number]; index: number; spellId: NonNullable<typeof entry.spellId> } => Boolean(entry.spellId))
          .map(({ spellId, index }) => {
          const spell = HEALER_ABILITIES[spellId];
          return interactive ? (
            <FocusButton
              key={spellId}
              context={context}
              focusId={rpgFocusId.spellSelected(spellId)}
              command={{ type: "run-action", action: { type: "spell-remove", spellId } }}
              className="rpg-tactical-spell"
              style={runAccentStyle(spell.color)}
              label={`Remove ${spell.name}`}
            ><b>{index + 1}</b><i>{spell.icon}</i><span>{spell.shortName}<small>Rank {run.spellRanks[spellId] ?? 0}</small></span><em>×</em></FocusButton>
          ) : (
            <div key={spellId} className="rpg-tactical-spell" style={runAccentStyle(spell.color)}>
              <b>{index + 1}</b><i>{spell.icon}</i><span>{spell.shortName}<small>Rank {run.spellRanks[spellId] ?? 0}</small></span>
            </div>
          );
        })}
        {!run.selectedSpellIds.length && <p className="rpg-empty-copy">Drafted spells appear here.</p>}
      </div>
    </section>
  );
}

function TacticalContinue({ context, focusId, action, label, disabled = false }: {
  readonly context: RpgRunUiContext;
  readonly focusId: string;
  readonly action: Parameters<RpgRunUiProps["onAction"]>[0];
  readonly label: string;
  readonly disabled?: boolean;
}) {
  return (
    <FocusButton context={context} focusId={focusId} command={{ type: "run-action", action }} className="rpg-tactical-continue" disabled={disabled}>
      <span>{label}</span><b>{DEFAULT_CONTROLLER_GLYPHS.confirm}</b>
    </FocusButton>
  );
}

function TacticalPartyDraft({ context }: { context: RpgRunUiContext }) {
  const { run } = context;
  const draft = run.partyDraft!;
  const canRemove = draft.waveIndex > 0;
  const canRecruit = run.roster.length < MAX_ACTIVE_ROSTER && draft.recruitedThisWaveIds.length < PARTY_RECRUITS_PER_WAVE;
  const finalWave = draft.waveIndex === PARTY_DRAFT_WAVE_COUNT - 1;
  const canContinue = finalWave
    ? run.roster.length === MAX_ACTIVE_ROSTER && run.roster.some((member) => member.role === "Tank")
    : run.roster.length + (PARTY_DRAFT_WAVE_COUNT - draft.waveIndex - 1) * PARTY_RECRUITS_PER_WAVE >= MAX_ACTIVE_ROSTER;
  return (
    <>
      <section className="rpg-tactical-section rpg-tactical-offers">
        <header><h3>Offers · wave {draft.waveIndex + 1}/{PARTY_DRAFT_WAVE_COUNT}</h3><span>{draft.recruitedThisWaveIds.length}/{PARTY_RECRUITS_PER_WAVE} picked</span></header>
        <div className="rpg-tactical-list">
          {draft.offers.map((candidate) => {
            const recruited = run.roster.some((member) => member.instanceId === candidate.candidateId);
            const disabled = (recruited && !canRemove) || (!recruited && !canRecruit);
            const role = partyRolePresentation(candidate.role);
            return (
              <FocusButton
                key={candidate.candidateId}
                context={context}
                focusId={rpgFocusId.partyOffer(candidate.candidateId)}
                command={{ type: "run-action", action: recruited ? { type: "party-remove", memberId: candidate.candidateId } : { type: "party-recruit", candidateId: candidate.candidateId } }}
                className={`rpg-tactical-offer rarity-${candidate.rarity}`}
                style={runAccentStyle(candidate.color)}
                disabled={disabled}
                pressed={recruited}
                label={`${recruited ? "Remove" : "Recruit"} ${candidate.name}, ${role.label}`}
              >
                <i>{role.icon}</i>
                <span><small>{candidate.rarity} · {role.label}</small><strong>{candidate.name}</strong><em>{candidate.className}</em></span>
                <b>HP {candidate.stats.maxHp}<small>ST {candidate.stats.singleTarget.toFixed(2)} · AOE {candidate.stats.areaDamage.toFixed(2)}</small></b>
                <u>{recruited ? canRemove ? "Remove" : "Locked" : disabled ? "Full" : "Recruit"}</u>
              </FocusButton>
            );
          })}
        </div>
      </section>
      <TacticalParty context={context} interactive={canRemove} />
      <TacticalContinue context={context} focusId={rpgFocusId.partyContinue} action={{ type: "party-next-wave" }} label={finalWave ? "Lock party" : "Reroll offers"} disabled={!canContinue} />
    </>
  );
}

function TacticalSpellDraft({ context }: { context: RpgRunUiContext }) {
  const { run } = context;
  const draft = run.spellDraft!;
  const canRemove = draft.waveIndex > 0;
  const canPick = run.selectedSpellIds.length < MAX_EQUIPPED_SPELLS && draft.pickedThisWaveIds.length < SPELL_PICKS_PER_WAVE;
  const finalWave = draft.waveIndex === SPELL_DRAFT_WAVE_COUNT - 1;
  return (
    <>
      <section className="rpg-tactical-section rpg-tactical-offers">
        <header><h3>Spells · wave {draft.waveIndex + 1}/{SPELL_DRAFT_WAVE_COUNT}</h3><span>{draft.pickedThisWaveIds.length}/{SPELL_PICKS_PER_WAVE} picked</span></header>
        <div className="rpg-tactical-list">
          {draft.offers.map((spellId) => {
            const spell = HEALER_ABILITIES[spellId];
            const selected = run.selectedSpellIds.includes(spellId);
            const disabled = (selected && !canRemove) || (!selected && !canPick);
            return (
              <FocusButton
                key={spellId}
                context={context}
                focusId={rpgFocusId.spellOffer(spellId)}
                command={{ type: "run-action", action: selected ? { type: "spell-remove", spellId } : { type: "spell-pick", spellId } }}
                className="rpg-tactical-offer is-spell"
                style={runAccentStyle(spell.color)}
                disabled={disabled}
                pressed={selected}
              >
                <i>{spell.icon}</i><span><small>{spell.targeting} · {spell.mana} mana</small><strong>{spell.name}</strong><em>{spell.description}</em></span><u>{selected ? canRemove ? "Remove" : "Locked" : disabled ? "Full" : "Learn"}</u>
              </FocusButton>
            );
          })}
        </div>
      </section>
      <TacticalSpellbook context={context} interactive={canRemove} />
      <TacticalContinue context={context} focusId={rpgFocusId.spellContinue} action={{ type: "spell-next-wave" }} label={finalWave ? "Lock spellbook" : "Reroll spells"} disabled={finalWave && !run.selectedSpellIds.length} />
    </>
  );
}

function TacticalBriefing({ context }: { context: RpgRunUiContext }) {
  const { run } = context;
  const challenge = run.phase === "challenge-briefing";
  const boss = currentBoss(run);
  return (
    <>
      <section className="rpg-tactical-hero" style={!challenge && boss ? runAccentStyle(boss.accent) : undefined}>
        <i>{challenge ? "◇" : boss?.icon ?? "♛"}</i>
        <small>{challenge ? "Hallway challenge" : "Boss chamber"}</small>
        <h2>{challenge ? run.currentChallenge?.objective.name : boss?.name}</h2>
        <p>{challenge ? "Success improves the next chest. Failure still opens the boss door." : boss?.briefing}</p>
      </section>
      {challenge && <ChallengeObjective run={run} />}
      <TacticalParty context={context} />
      <TacticalContinue
        context={context}
        focusId={challenge ? rpgFocusId.challengeStart : rpgFocusId.bossStart}
        action={challenge ? { type: "challenge-start" } : { type: "boss-start" }}
        label={challenge ? "Start challenge" : "Enter chamber"}
      />
    </>
  );
}

function TacticalLiveParty({ live }: { live: RpgLiveCombatUi }) {
  return (
    <section className="rpg-tactical-section rpg-live-party">
      <header><h3>Live party</h3><span>{live.party.filter((member) => member.hp > 0).length}/{live.party.length} standing</span></header>
      <div className="rpg-live-party-grid">
        {live.party.map((member) => {
          const health = Math.max(0, Math.min(100, member.hp / Math.max(1, member.maxHp) * 100));
          const selected = member.id === live.selectedMemberId;
          return (
            <button
              key={member.id}
              type="button"
              className={`${selected ? "is-selected" : ""} ${member.hp <= 0 ? "is-down" : ""}`.trim()}
              onClick={() => live.onSelectMember?.(member.id)}
              disabled={member.hp <= 0}
              aria-pressed={selected}
              aria-label={`Target ${member.name}, ${Math.ceil(member.hp)} of ${member.maxHp} health`}
            >
              <i style={{ "--rpg-member-color": member.color } as CSSProperties}>{member.name[0]}</i>
              <span><strong>{member.name}</strong><small>{member.className}</small><em><b style={{ width: `${health}%` }} /></em></span>
              <u>{member.hp <= 0 ? "DOWN" : `${Math.ceil(member.hp)} / ${member.maxHp}`}</u>
            </button>
          );
        })}
      </div>
    </section>
  );
}

function TacticalLiveSpellbook({ context, live }: { context: RpgRunUiContext; live: RpgLiveCombatUi }) {
  const castProgress = live.activeCast
    ? Math.max(0, Math.min(1, (live.time - live.activeCast.startedAt) / Math.max(0.001, live.activeCast.completesAt - live.activeCast.startedAt)))
    : 0;
  return (
    <section className="rpg-tactical-section rpg-live-spells">
      <header><h3>Spell arsenal</h3><span>{Math.ceil(live.mana)} / {live.maxMana} mana</span></header>
      <div className="rpg-live-resource-bar"><i style={{ width: `${Math.max(0, Math.min(100, live.mana / Math.max(1, live.maxMana) * 100))}%` }} /></div>
      <div className="rpg-live-resources">
        <span><b>Verdancy</b>{live.spellResources.verdancy}/5</span>
        <span><b>Tidal Surge</b>{live.spellResources.tidalSurge}/2</span>
        <span><b>Conviction</b>{live.spellResources.conviction}/3</span>
        <span><b>Chronoshards</b>{live.spellResources.chronoshards}/3</span>
      </div>
      {live.activeCast && (
        <div className="rpg-live-cast" style={{ "--rpg-cast-progress": `${castProgress * 100}%` } as CSSProperties}>
          <span>Casting <b>{HEALER_ABILITIES[live.activeCast.abilityId].name}</b></span><i><em /></i>
        </div>
      )}
      <div className="rpg-live-spell-grid">
        {ABILITY_LOADOUT_SLOTS.map((slotId, index) => {
          const spellId = context.run.abilityLoadout[slotId];
          if (!spellId) return <div key={slotId} className="rpg-live-spell is-empty"><b>{index + 1}</b><span>Empty</span></div>;
          const spell = HEALER_ABILITIES[spellId];
          const cooldown = Math.max(0, live.cooldowns[slotId] - live.time, live.globalCooldownUntil - live.time);
          const selected = live.party.find((member) => member.id === live.selectedMemberId);
          const disabled = !live.onCastAbility || live.activeCast !== null || cooldown > 0 || live.mana < spell.mana
            || (spell.targeting === "ally" && (!selected || selected.hp <= 0))
            || (spell.pulseKind === "cleanse" && !selected?.debuffs.length);
          return (
            <button
              key={slotId}
              type="button"
              className={`rpg-live-spell ${cooldown > 0 ? "is-cooling" : ""}`}
              style={{ "--rpg-accent": spell.color } as CSSProperties}
              onClick={() => live.onCastAbility?.(slotId)}
              disabled={disabled}
              aria-label={`${spell.name}, ${cooldown > 0 ? `${cooldown.toFixed(1)} seconds remaining` : "ready"}`}
            >
              <b>{ABILITY_CONTROLLER_BINDINGS[slotId].glyph}</b><i>{spell.icon}</i><span><strong>{spell.shortName}</strong><small>{spell.mana} mana · Rank {context.run.spellRanks[spellId] ?? 0}</small></span>
              <u>{cooldown > 0 ? cooldown.toFixed(1) : "Ready"}</u>
            </button>
          );
        })}
      </div>
    </section>
  );
}

function TacticalLive({ context }: { context: RpgRunUiContext }) {
  const { run } = context;
  const boss = currentBoss(run);
  const live = context.liveCombat;
  return (
    <>
      {run.phase === "challenge-active" ? <ChallengeObjective run={run} /> : (
        <section className="rpg-tactical-hero is-live" style={boss ? runAccentStyle(boss.accent) : undefined}>
          <i>{boss?.icon ?? "♛"}</i><small>Boss battle</small><h2>{boss?.name}</h2><p>{boss?.summary}</p>
        </section>
      )}
      {live ? <TacticalLiveParty live={live} /> : <TacticalParty context={context} />}
      {live ? <TacticalLiveSpellbook context={context} live={live} /> : <TacticalSpellbook context={context} />}
      <p className="rpg-controller-hint"><b>D-pad</b> Target <i /> <b>Face buttons</b> Cast</p>
    </>
  );
}

function TacticalCleared({ context }: { context: RpgRunUiContext }) {
  return (
    <>
      <section className="rpg-tactical-hero rpg-tactical-cleared">
        <i>↑</i><small>North gate open</small><h2>Room cleared</h2><p>Cross the far doorway. Health and fallen companions carry forward.</p>
      </section>
      <TacticalParty context={context} />
      <TacticalContinue context={context} focusId={rpgFocusId.rewardOpen} action={{ type: "reward-open" }} label="Open chest" />
    </>
  );
}

function TacticalRewards({ context }: { context: RpgRunUiContext }) {
  const chest = context.run.pendingReward;
  if (!chest) return null;
  return (
    <section className="rpg-tactical-section">
      <header><h3>Choose one reward</h3><span>Chest +{chest.quality}</span></header>
      <div className="rpg-tactical-rewards">
        {chest.choices.map((choice) => {
          const summary = rewardSummary(choice);
          return (
            <FocusButton key={choice.id} context={context} focusId={rpgFocusId.rewardChoice(choice.id)} command={{ type: "run-action", action: { type: "reward-choose", choiceId: choice.id } }} className="rpg-tactical-reward" style={runAccentStyle(summary.accent)} label={choice.kind === "run-gear" ? `Claim ${choice.item.name}. ${gearComparisonLabel(context.run, choice.item)}` : `Claim ${choice.label}. ${summary.detail}`}>
              <i>{summary.icon}</i><span><small>{summary.eyebrow}</small><strong>{choice.label}</strong><p>{summary.detail}</p>{choice.kind === "run-gear" && <GearStatComparison run={context.run} item={choice.item} />}</span><b>Claim</b>
            </FocusButton>
          );
        })}
      </div>
    </section>
  );
}

function TacticalShop({ context }: { context: RpgRunUiContext }) {
  const { run } = context;
  const shop = run.shop;
  if (!shop) return null;
  const needsRest = run.playerHp > 0 && run.playerHp < 100
    || run.roster.some((member) => member.hp > 0 && member.hp < member.stats.maxHp);
  return (
    <>
      <section className="rpg-tactical-section">
        <header><h3>Buy gear</h3><span>◆ {run.currency}</span></header>
        <div className="rpg-tactical-shop-grid">
          {shop.offers.map((offer) => (
            <GearCard key={offer.id} run={run} item={offer.item} price={offer.price} action={
              <FocusButton context={context} focusId={rpgFocusId.shopOffer(offer.id)} command={{ type: "run-action", action: { type: "shop-buy", offerId: offer.id } }} className="rpg-card-action" disabled={offer.sold || run.currency < offer.price} label={`${offer.sold ? `${offer.item.name} sold` : `Buy ${offer.item.name} for ${offer.price} gold`}. ${gearComparisonLabel(run, offer.item)}`}>
                <span>{offer.sold ? "Sold" : "Buy"}</span>
              </FocusButton>
            } />
          ))}
        </div>
      </section>
      <section className="rpg-tactical-section">
        <header><h3>Bag & services</h3><span>{run.bag.length} stored</span></header>
        <div className="rpg-tactical-list">
          {run.bag.map((item) => (
            <FocusButton key={item.id} context={context} focusId={rpgFocusId.shopSell(item.id)} command={{ type: "run-action", action: { type: "shop-sell", itemId: item.id } }} className="rpg-service-row">
              <span><small>Sell gear</small>{item.name}</span><b>◆ {item.sellPrice}</b>
            </FocusButton>
          ))}
          <FocusButton context={context} focusId={rpgFocusId.shopRest} command={{ type: "run-action", action: { type: "shop-rest" } }} className="rpg-service-row" disabled={!needsRest || run.currency < shop.restCost}>
            <span><small>Restore living party</small>Rest</span><b>◆ {shop.restCost}</b>
          </FocusButton>
          {run.roster.filter((member) => member.hp <= 0).map((member) => (
            <FocusButton key={member.instanceId} context={context} focusId={rpgFocusId.shopRevive(member.instanceId)} command={{ type: "run-action", action: { type: "shop-revive", memberId: member.instanceId } }} className="rpg-service-row" disabled={run.currency < shop.reviveCost}>
              <span><small>Return at 50% HP</small>Revive {member.name}</span><b>◆ {shop.reviveCost}</b>
            </FocusButton>
          ))}
        </div>
      </section>
      <TacticalContinue context={context} focusId={rpgFocusId.shopLeave} action={{ type: "shop-leave" }} label="Leave shop" />
    </>
  );
}

function TacticalTerminal({ context }: { context: RpgRunUiContext }) {
  const victory = context.run.phase === "victory";
  return (
    <section className={`rpg-tactical-terminal ${victory ? "is-victory" : "is-defeat"}`}>
      <i>{victory ? "♛" : "◇"}</i><small>{victory ? "Run complete" : "Run ended"}</small><h2>{victory ? "Victory" : "Party fallen"}</h2>
      <p>{context.run.bossesDefeated} bosses · {context.run.selectedSpellIds.length} spells · ◆ {context.run.currency}</p>
      <FocusButton context={context} focusId={rpgFocusId.restartRun} command={{ type: "restart-run" }} className="rpg-tactical-continue" disabled={!context.onRestartRun}><span>New run</span><b>{DEFAULT_CONTROLLER_GLYPHS.confirm}</b></FocusButton>
      <FocusButton context={context} focusId={rpgFocusId.exitRun} command={{ type: "exit-run" }} className="rpg-secondary-action" disabled={!context.onExitRun}>Mode select</FocusButton>
    </section>
  );
}

/** Secondary-display tactical projection. Same semantic focus IDs as top overlay. */
export function RpgRunTacticalPanel(props: RpgRunUiProps) {
  const context = createUiContext(props);
  const run = props.run;
  return (
    <aside className={`rpg-run-tactical ${props.className ?? ""}`.trim()} aria-label="RPG roguelike tactics">
      <RunHeader run={run} compact />
      <RoutePips run={run} />
      <div className="rpg-tactical-body">
        {run.phase === "party-draft" && <TacticalPartyDraft context={context} />}
        {run.phase === "spell-draft" && <TacticalSpellDraft context={context} />}
        {(run.phase === "challenge-briefing" || run.phase === "boss-briefing") && <TacticalBriefing context={context} />}
        {(run.phase === "challenge-active" || run.phase === "boss-combat") && <TacticalLive context={context} />}
        {run.phase === "boss-cleared" && <TacticalCleared context={context} />}
        {run.phase === "reward" && <TacticalRewards context={context} />}
        {run.phase === "shop" && <TacticalShop context={context} />}
        {(run.phase === "victory" || run.phase === "defeat") && <TacticalTerminal context={context} />}
      </div>
    </aside>
  );
}
