/**
 * @file Goddess Boss panel — challenge divine realm bosses.
 * @copyright nhcarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */
/* eslint-disable max-lines -- Panel with sub-component, modal, and zone filter */
/* eslint-disable max-lines-per-function -- Complex component with many render paths */
/* eslint-disable complexity -- Boss card requires many conditional render paths */
/* eslint-disable max-statements -- Panel requires many variable declarations */
/* eslint-disable react/no-multi-comp -- Sub-components are tightly coupled to this panel */
import { type JSX, useState } from "react";
import { useGame } from "../../context/gameContext.js";
import type {
  GoddessBoss,
  GoddessBossChallengeResponse,
  GoddessZone,
} from "@elysium/types";

interface GoddessBossCardProperties {
  readonly boss:          GoddessBoss;
  readonly onChallenge:   (bossId: string)=> void;
  readonly isChallenging: boolean;
  readonly unlockHint:    string | undefined;
  readonly formatNumber:  (n: number)=> string;
  readonly formatInteger: (n: number)=> string;
}

/**
 * Renders a single goddess boss card.
 * @param props - The boss card properties.
 * @param props.boss - The boss data.
 * @param props.onChallenge - Callback to challenge this boss.
 * @param props.isChallenging - Whether this boss is currently being challenged.
 * @param props.unlockHint - Optional hint for how to unlock this boss.
 * @param props.formatNumber - The number formatting utility function.
 * @param props.formatInteger - The integer formatting utility function.
 * @returns The JSX element.
 */
const GoddessBossCard = ({
  boss,
  onChallenge,
  isChallenging,
  unlockHint,
  formatNumber,
  formatInteger,
}: GoddessBossCardProperties): JSX.Element => {
  const canChallenge
    = (boss.status === "available" || boss.status === "in_progress")
    && !isChallenging;

  const hpRatio = boss.currentHp / boss.maxHp;
  const hpPercent = hpRatio * 100;

  function handleChallenge(): void {
    onChallenge(boss.id);
  }

  return (
    <div className={`boss-card boss-${boss.status}`}>
      <div className="boss-info">
        <h3>{boss.name}</h3>
        <p>{boss.description}</p>
        {boss.status === "locked" && unlockHint !== undefined
          ? <p className="unlock-hint">{unlockHint}</p>
          : null}
        {boss.consecrationRequirement > 0
          ? <p className="consecration-requirement">
            {"🕊️ Requires Consecration "}
            {boss.consecrationRequirement}
          </p>
          : null}
      </div>

      {boss.status !== "locked" && boss.status !== "defeated"
        ? <div className="boss-hp">
          <div className="hp-bar">
            <div
              className="hp-fill"
              style={{ width: `${hpPercent.toFixed(1)}%` }}
            />
          </div>
          <span className="hp-text">
            {formatNumber(boss.currentHp)}
            {" / "}
            {formatNumber(boss.maxHp)}
            {" HP"}
          </span>
        </div>
        : null}

      <div className="boss-meta">
        <span className="boss-dps">
          {"💢 Boss DPS: "}
          {formatNumber(boss.damagePerSecond)}
        </span>
      </div>

      <div className="boss-rewards">
        {boss.prayersReward > 0
          && <span>
            {"🙏 "}
            {formatNumber(boss.prayersReward)}
          </span>
        }
        {boss.divinityReward > 0
          && <span>
            {"✨ "}
            {formatInteger(boss.divinityReward)}
            {" Divinity"}
          </span>
        }
        {boss.stardustReward > 0
          && <span>
            {"⭐ "}
            {formatInteger(boss.stardustReward)}
            {" Stardust"}
          </span>
        }
        {boss.equipmentRewards.length > 0
          && <span>
            {"🗡️ "}
            {boss.equipmentRewards.length}
            {" Equipment"}
          </span>
        }
        {boss.status !== "defeated"
        && boss.bountyDivinity > 0
        && boss.bountyDivinityClaimed !== true
          ? <span className="boss-bounty">
            {"✨ "}
            {boss.bountyDivinity}
            {" Divinity (first kill)"}
          </span>
          : null}
      </div>

      {boss.status === "available" || boss.status === "in_progress"
        ? <button
          className="attack-button"
          disabled={!canChallenge}
          onClick={handleChallenge}
          type="button"
        >
          {isChallenging
            ? "⚔️ Battling…"
            : "⚔️ Challenge"}
        </button>
        : null}

      {boss.status === "defeated"
        ? <span className="boss-badge defeated">{"☠️ Defeated"}</span>
        : null}
    </div>
  );
};

interface GoddessBattleModalProperties {
  readonly result:        GoddessBossChallengeResponse;
  readonly onDismiss:     ()=> void;
  readonly formatNumber:  (n: number)=> string;
  readonly formatInteger: (n: number)=> string;
}

/**
 * Renders the goddess battle result modal overlay.
 * @param props - The modal properties.
 * @param props.result - The battle result data.
 * @param props.onDismiss - Callback to dismiss the modal.
 * @param props.formatNumber - The number formatting utility function.
 * @param props.formatInteger - The integer formatting utility function.
 * @returns The JSX element.
 */
const GoddessBattleModal = ({
  result,
  onDismiss,
  formatNumber,
  formatInteger,
}: GoddessBattleModalProperties): JSX.Element => {
  return (
    <div aria-modal="true" className="battle-modal-overlay" role="dialog">
      <div className="battle-modal">
        <h2 className="battle-modal-title">
          {result.won
            ? "⚔️ Victory!"
            : "💀 Defeated!"}
        </h2>

        <div className="battle-stats">
          <div className="battle-stat">
            <span className="stat-label">{"⚔️ Your Party DPS"}</span>
            <span className="stat-value">{formatNumber(result.partyDPS)}</span>
          </div>
          <div className="battle-stat">
            <span className="stat-label">{"💢 Boss DPS"}</span>
            <span className="stat-value">{formatNumber(result.bossDPS)}</span>
          </div>
          <div className="battle-stat">
            <span className="stat-label">{"❤️ Boss HP Before"}</span>
            <span className="stat-value">
              {formatNumber(result.bossHpBefore)}
              {" / "}
              {formatNumber(result.bossMaxHp)}
            </span>
          </div>
          <div className="battle-stat">
            <span className="stat-label">{"❤️ Boss HP After"}</span>
            <span className="stat-value">{formatNumber(result.bossNewHp)}</span>
          </div>
          <div className="battle-stat">
            <span className="stat-label">{"🛡️ Party HP Remaining"}</span>
            <span className="stat-value">
              {formatNumber(result.partyHpRemaining)}
              {" / "}
              {formatNumber(result.partyMaxHp)}
            </span>
          </div>
        </div>

        {result.won && result.rewards !== undefined
          ? <div className="battle-rewards">
            <h3>{"Rewards"}</h3>
            {result.rewards.prayers > 0
              ? <p>
                {"🙏 "}
                {formatNumber(result.rewards.prayers)}
                {" Prayers"}
              </p>
              : null}
            {result.rewards.divinity > 0
              ? <p>
                {"✨ "}
                {formatInteger(result.rewards.divinity)}
                {" Divinity"}
              </p>
              : null}
            {result.rewards.stardust > 0
              ? <p>
                {"⭐ "}
                {formatInteger(result.rewards.stardust)}
                {" Stardust"}
              </p>
              : null}
            {result.rewards.bountyDivinity > 0
              ? <p className="bounty-reward">
                {"✨ "}
                {formatInteger(result.rewards.bountyDivinity)}
                {" Divinity (first kill bonus!)"}
              </p>
              : null}
            {result.rewards.upgradeIds.length > 0
              ? <p>
                {"🔓 "}
                {result.rewards.upgradeIds.length}
                {" Upgrade(s) unlocked"}
              </p>
              : null}
            {result.rewards.equipmentIds.length > 0
              ? <p>
                {"🗡️ "}
                {result.rewards.equipmentIds.length}
                {" Equipment item(s) gained"}
              </p>
              : null}
          </div>
          : null}

        {result.casualties !== undefined && result.casualties.length > 0
          ? <div className="battle-casualties">
            <h3>{"Casualties"}</h3>
            {result.casualties.map((casualty) => {
              return (
                <p key={casualty.discipleId}>
                  {casualty.killed}
                  {" "}
                  {casualty.discipleId}
                  {" lost"}
                </p>
              );
            })}
          </div>
          : null}

        <button
          className="dismiss-button"
          onClick={onDismiss}
          type="button"
        >
          {"Dismiss"}
        </button>
      </div>
    </div>
  );
};

/**
 * Renders the Goddess Boss panel with zone filtering and battle result modal.
 * @returns The JSX element.
 */
const GoddessBossPanel = (): JSX.Element => {
  const {
    state,
    challengeGoddessBoss,
    goddessBattleResult,
    dismissGoddessBattle,
    formatNumber,
    formatInteger,
    goddessPreview,
  } = useGame();

  const [ challengingBossId, setChallengingBossId ] = useState<string | null>(
    null,
  );
  const [ activeZoneId, setActiveZoneId ] = useState<string | null>(() => {
    return sessionStorage.getItem("elysium_goddess_boss_zone");
  });

  if (state === null) {
    return (
      <section className="panel">
        <p>{"Loading..."}</p>
      </section>
    );
  }

  const goddess = state.goddess ?? goddessPreview;

  if (goddess === undefined) {
    return (
      <section className="panel">
        <p>{"The Goddess expansion is not yet unlocked."}</p>
      </section>
    );
  }

  const { bosses, quests, zones } = goddess;

  async function handleChallenge(bossId: string): Promise<void> {
    setChallengingBossId(bossId);
    try {
      await challengeGoddessBoss(bossId);
    } finally {
      setChallengingBossId(null);
    }
  }

  function handleChallengeClick(bossId: string): void {
    void handleChallenge(bossId);
  }

  function handleZoneSelect(zoneId: string): void {
    setActiveZoneId(zoneId);
    sessionStorage.setItem("elysium_goddess_boss_zone", zoneId);
  }

  function handleShowAll(): void {
    setActiveZoneId(null);
    sessionStorage.removeItem("elysium_goddess_boss_zone");
  }

  const filteredBosses = activeZoneId === null
    ? bosses
    : bosses.filter((boss) => {
      return boss.zoneId === activeZoneId;
    });

  const bossUnlockHints = new Map<string, string>();
  for (const zone of zones) {
    const { id: zoneId, unlockBossId, unlockQuestId } = zone;
    const zoneBosses = bosses.filter((boss) => {
      return boss.zoneId === zoneId;
    });
    for (let index = 0; index < zoneBosses.length; index = index + 1) {
      const boss = zoneBosses[index];
      if (boss === undefined || boss.status !== "locked") {
        continue;
      }
      if (index === 0) {
        const parts: Array<string> = [];
        if (unlockBossId !== null) {
          const gateBoss = bosses.find((candidate) => {
            return candidate.id === unlockBossId;
          });
          if (gateBoss !== undefined) {
            parts.push(`⚔️ Defeat: ${gateBoss.name}`);
          }
        }
        if (unlockQuestId !== null) {
          const gateQuest = quests.find((candidate) => {
            return candidate.id === unlockQuestId;
          });
          if (gateQuest !== undefined) {
            parts.push(`📜 Complete: ${gateQuest.name}`);
          }
        }
        if (parts.length > 0) {
          bossUnlockHints.set(boss.id, parts.join(" & "));
        }
      } else {
        const previousBoss = zoneBosses[index - 1];
        if (previousBoss !== undefined) {
          bossUnlockHints.set(boss.id, `⚔️ Defeat: ${previousBoss.name} first`);
        }
      }
    }
  }

  const activeZoneData: GoddessZone | undefined = activeZoneId === null
    ? undefined
    : zones.find((zone) => {
      return zone.id === activeZoneId;
    });

  return (
    <section className="panel goddess-boss-panel">
      <div className="panel-header">
        <h2>{"⚔️ Goddess Bosses"}</h2>
      </div>

      <div className="zone-selector">
        <button
          className={`zone-tab${activeZoneId === null
            ? " zone-tab-active"
            : ""}`}
          onClick={handleShowAll}
          type="button"
        >
          {"All Zones"}
        </button>
        {zones.map((zone) => {
          function handleSelect(): void {
            handleZoneSelect(zone.id);
          }
          return (
            <button
              className={`zone-tab${zone.id === activeZoneId
                ? " zone-tab-active"
                : ""}`}
              key={zone.id}
              onClick={handleSelect}
              title={zone.description}
              type="button"
            >
              <span aria-hidden="true">{zone.emoji}</span>
              <span className="zone-name">{zone.name}</span>
            </button>
          );
        })}
      </div>

      {activeZoneData?.status === "locked"
        ? <div className="exploration-zone-locked-hint">
          <p>{"🔒 This zone is locked."}</p>
          {activeZoneData.unlockBossId === null
            ? null
            : <p>
              {"⚔️ Defeat: "}
              {bosses.find((boss) => {
                return boss.id === activeZoneData.unlockBossId;
              })?.name ?? activeZoneData.unlockBossId}
            </p>}
          {activeZoneData.unlockQuestId === null
            ? null
            : <p>
              {"📜 Complete: "}
              {quests.find((quest) => {
                return quest.id === activeZoneData.unlockQuestId;
              })?.name ?? activeZoneData.unlockQuestId}
            </p>}
        </div>
        : null}

      <div className="boss-list">
        {filteredBosses.map((boss) => {
          return (
            <GoddessBossCard
              boss={boss}
              formatInteger={formatInteger}
              formatNumber={formatNumber}
              isChallenging={challengingBossId === boss.id}
              key={boss.id}
              onChallenge={handleChallengeClick}
              unlockHint={bossUnlockHints.get(boss.id)}
            />
          );
        })}
        {filteredBosses.length === 0
          ? <p className="empty-zone">{"No bosses to show in this zone."}</p>
          : null}
      </div>

      {goddessBattleResult === null
        ? null
        : <GoddessBattleModal
          formatInteger={formatInteger}
          formatNumber={formatNumber}
          onDismiss={dismissGoddessBattle}
          result={goddessBattleResult}
        />}
    </section>
  );
};

export { GoddessBossPanel };
