/**
 * @file Boss panel component for viewing and challenging zone bosses.
 * @copyright nhcarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */
/* eslint-disable react/no-multi-comp -- Sub-component is tightly coupled to the panel */
/* 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 -- Boss panel requires many variable declarations */
/* eslint-disable max-lines -- Boss panel with sub-component and helper function */
import { type JSX, useState } from "react";
import { useGame } from "../../context/gameContext.js";
import { cdnImage } from "../../utils/cdn.js";
import { LockToggle } from "../ui/lockToggle.js";
import { ZoneSelector } from "./zoneSelector.js";
import type { Boss, GameState } from "@elysium/types";

interface BossCardProperties {
  readonly boss:          Boss;
  readonly prestigeCount: number;
  readonly onChallenge:   (bossId: string)=> void;
  readonly isChallenging: boolean;
  readonly unlockHint:    string | undefined;
  readonly formatNumber:  (n: number)=> string;
}

/**
 * Renders a single boss card.
 * @param props - The boss card properties.
 * @param props.boss - The boss data.
 * @param props.prestigeCount - The current prestige count for lock checking.
 * @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.
 * @returns The JSX element.
 */
const BossCard = ({
  boss,
  prestigeCount,
  onChallenge,
  isChallenging,
  unlockHint,
  formatNumber,
}: BossCardProperties): JSX.Element => {
  const scaled = boss.currentHp * 100;
  const hpPercent = scaled / boss.maxHp;
  const isPrestigeLocked = boss.prestigeRequirement > prestigeCount;
  const canChallenge
    = (boss.status === "available" || boss.status === "in_progress")
    && !isChallenging;

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

  return (
    <div className={`boss-card boss-${boss.status}`}>
      <img
        alt={boss.name}
        className="card-thumbnail"
        src={cdnImage("bosses", boss.id)}
      />
      <div className="boss-info">
        <h3>{boss.name}</h3>
        <p>{boss.description}</p>
        {isPrestigeLocked && boss.status === "locked"
          ? <p className="prestige-lock">
            {"🔒 Requires Prestige "}
            {boss.prestigeRequirement}
          </p>
          : null}
        {!isPrestigeLocked
        && boss.status === "locked"
        && unlockHint !== undefined
          ? <p className="unlock-hint">{unlockHint}</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>
      }

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

      <div className="boss-rewards">
        <span>
          {"🪙 "}
          {formatNumber(boss.goldReward)}
        </span>
        {boss.essenceReward > 0
          && <span>
            {"✨ "}
            {formatNumber(boss.essenceReward)}
          </span>
        }
        {boss.crystalReward > 0
          && <span>
            {"💎 "}
            {formatNumber(boss.crystalReward)}
          </span>
        }
        {boss.equipmentRewards.length > 0
          && <span>
            {"🗡️ "}
            {boss.equipmentRewards.length}
            {" Equipment"}
          </span>
        }
        {boss.status !== "defeated"
        && boss.bountyRunestones > 0
        && boss.bountyRunestonesClaimed !== true
          && <span className="boss-bounty">
            {"🔮 "}
            {boss.bountyRunestones}
            {" (first kill)"}
          </span>
        }
      </div>

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

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

/**
 * Computes party DPS and HP from the current game state.
 * @param state - The full game state.
 * @returns The computed party DPS and HP values.
 */
const computePartyStats = (
  state: GameState,
): {
  partyDps: number;
  partyHp:  number;
} => {
  const { upgrades, adventurers, equipment, prestige } = state;
  let globalMultiplier = 1;
  for (const upgrade of upgrades) {
    const { purchased, target, multiplier } = upgrade;
    if (purchased && target === "global") {
      globalMultiplier = globalMultiplier * multiplier;
    }
  }
  const prestigeBonus = prestige.count * 0.1;
  const prestigeMultiplier = 1 + prestigeBonus;
  const equipmentCombatMultiplier = equipment.
    filter((item) => {
      return item.equipped && item.bonus.combatMultiplier !== undefined;
    }).
    reduce((multiplier, item) => {
      return multiplier * (item.bonus.combatMultiplier ?? 1);
    }, 1);

  let partyDps = 0;
  let partyHp = 0;
  for (const adventurer of adventurers) {
    const { count, id: adventurerId, combatPower, level } = adventurer;
    if (count === 0) {
      continue;
    }
    let adventurerMultiplier = 1;
    for (const upgrade of upgrades) {
      const {
        purchased,
        target,
        multiplier,
        adventurerId: upgradeAdventurerId,
      } = upgrade;
      if (
        purchased
        && target === "adventurer"
        && upgradeAdventurerId === adventurerId
      ) {
        adventurerMultiplier = adventurerMultiplier * multiplier;
      }
    }
    const dps
      = combatPower
      * count
      * adventurerMultiplier
      * globalMultiplier
      * prestigeMultiplier;
    partyDps = partyDps + dps;
    const hp = level * 50 * count;
    partyHp = partyHp + hp;
  }
  partyDps = partyDps * equipmentCombatMultiplier;
  return { partyDps, partyHp };
};

/**
 * Renders the boss panel with zone selection and boss list.
 * @returns The JSX element.
 */
const BossPanel = (): JSX.Element => {
  const {
    state,
    challengeBoss,
    formatNumber,
    toggleAutoBoss,
    autoBossLastResult,
    autoBossError,
    bossError,
  } = useGame();
  const [ challengingBossId, setChallengingBossId ] = useState<string | null>(
    null,
  );
  const [ activeZoneId, setActiveZoneId ] = useState(() => {
    return sessionStorage.getItem("elysium_boss_zone") ?? "verdant_vale";
  });
  const [ showLocked, setShowLocked ] = useState(true);

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

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

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

  const { zones, bosses, quests, autoBoss, prestige: playerPrestige } = state;

  const activeZone = zones.find((zone) => {
    return zone.id === activeZoneId;
  });
  const zoneIsLocked = activeZone?.status === "locked";
  const unlockBoss = activeZone?.unlockBossId === null
    || activeZone?.unlockBossId === undefined
    ? undefined
    : bosses.find((boss) => {
      return boss.id === activeZone.unlockBossId;
    });
  const unlockQuest = activeZone?.unlockQuestId === null
    || activeZone?.unlockQuestId === undefined
    ? undefined
    : quests.find((quest) => {
      return quest.id === activeZone.unlockQuestId;
    });
  const zoneBosses = bosses.filter((boss) => {
    return boss.zoneId === activeZoneId;
  });
  const lockedCount = zoneBosses.filter((boss) => {
    return boss.status === "locked";
  }).length;
  const visibleBosses = showLocked
    ? zoneBosses
    : zoneBosses.filter((boss) => {
      return boss.status !== "locked";
    });

  const bossUnlockHints = new Map<string, string>();
  for (const zone of zones) {
    const { id: zoneId, unlockBossId, unlockQuestId } = zone;
    const allZoneBosses = bosses.filter((boss) => {
      return boss.zoneId === zoneId;
    });
    for (let index = 0; index < allZoneBosses.length; index = index + 1) {
      const boss = allZoneBosses[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 = allZoneBosses[index - 1];
        if (previousBoss !== undefined) {
          bossUnlockHints.set(boss.id, `⚔️ Defeat: ${previousBoss.name} first`);
        }
      }
    }
  }

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

  function handleToggle(): void {
    setShowLocked((current) => {
      return !current;
    });
  }

  const autoBossOn = autoBoss === true;
  const { partyDps, partyHp } = computePartyStats(state);
  const { count: prestigeCount } = playerPrestige;

  return (
    <section className="panel boss-panel">
      <div className="panel-header">
        <h2>{"Boss Encounters"}</h2>
        <div className="panel-header-controls">
          <button
            className={`auto-toggle-btn ${
              autoBossOn
                ? "auto-toggle-on"
                : "auto-toggle-off"
            }`}
            onClick={toggleAutoBoss}
            title="Automatically challenge the highest available boss"
            type="button"
          >
            {"🤖 Auto: "}
            {autoBossOn
              ? "ON"
              : "OFF"}
          </button>
          <LockToggle
            lockedCount={lockedCount}
            onToggle={handleToggle}
            showLocked={showLocked}
          />
        </div>
      </div>

      {bossError === null
        ? null
        : <p className="auto-boss-error">
          {"⚠️ "}
          {bossError}
        </p>
      }
      {autoBossError === null
        ? null
        : <p className="auto-boss-error">
          {"⚠️ Auto-boss stopped: "}
          {autoBossError}
        </p>
      }
      {autoBossLastResult !== null && autoBossError === null
        ? <p className="auto-boss-status">
          {"🤖 Last fight: "}
          {autoBossLastResult.bossName}
          {autoBossLastResult.won
            ? " — ✅ Won"
            : " — ❌ Lost"}
        </p>
        : null}

      <ZoneSelector
        activeZoneId={activeZoneId}
        onSelectZone={handleZoneSelect}
        zones={zones}
      />

      {zoneIsLocked && (unlockBoss !== undefined || unlockQuest !== undefined)
        ? <div className="exploration-zone-locked-hint">
          <p>{"🔒 This zone is locked. Unlock bosses by:"}</p>
          {unlockBoss === undefined
            ? null
            : <p>
              {"⚔️ Defeat: "}
              {unlockBoss.name}
            </p>
          }
          {unlockQuest === undefined
            ? null
            : <p>
              {"📜 Complete: "}
              {unlockQuest.name}
            </p>
          }
        </div>
        : null
      }

      <div className="party-combat-stats">
        <div className="combat-stat">
          <span className="stat-label">{"⚔️ Party DPS"}</span>
          <span className="stat-value">{formatNumber(partyDps)}</span>
        </div>
        <div className="combat-stat">
          <span className="stat-label">{"❤️ Party HP"}</span>
          <span className="stat-value">{formatNumber(partyHp)}</span>
        </div>
      </div>

      <div className="boss-list">
        {visibleBosses.map((boss) => {
          const { id: bossId } = boss;
          return (
            <BossCard
              boss={boss}
              formatNumber={formatNumber}
              isChallenging={challengingBossId === bossId}
              key={bossId}
              onChallenge={handleChallengeClick}
              prestigeCount={prestigeCount}
              unlockHint={bossUnlockHints.get(bossId)}
            />
          );
        })}
        {visibleBosses.length === 0
          && <p className="empty-zone">{"No bosses to show in this zone."}</p>
        }
      </div>
    </section>
  );
};

export { BossPanel };
