/**
 * @file Adventurer panel component for hiring and managing adventurers.
 * @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 -- Complex component with many render paths */
import { type JSX, useState } from "react";
import { useGame } from "../../context/gameContext.js";
import { computeEffectiveAdventurerStats } from "../../engine/tick.js";
import { cdnImage } from "../../utils/cdn.js";
import { LockToggle } from "../ui/lockToggle.js";
import type { Adventurer } from "@elysium/types";

type BatchSize = 1 | 5 | 10 | 25 | 100 | "max";
const batchOptions: Array<BatchSize> = [ 1, 5, 10, 25, 100, "max" ];

/**
 * Parses a localStorage string back into a valid BatchSize, defaulting to 1.
 * @param stored - The raw string from localStorage (or null if absent).
 * @returns A valid BatchSize value.
 */
const parseBatchSize = (stored: string | null): BatchSize => {
  if (stored === "max") {
    return "max";
  }
  const numeric = Number(stored);
  if (numeric === 5) {
    return 5;
  }
  if (numeric === 10) {
    return 10;
  }
  if (numeric === 25) {
    return 25;
  }
  if (numeric === 100) {
    return 100;
  }
  return 1;
};

/**
 * Computes the total cost to buy a batch of adventurers.
 * @param adventurer - The adventurer to buy.
 * @param quantity - The number to buy.
 * @returns The total gold cost.
 */
const computeBatchCost = (adventurer: Adventurer, quantity: number): number => {
  let total = 0;
  for (let index = 0; index < quantity; index = index + 1) {
    const cost = adventurer.baseCost * Math.pow(1.15, adventurer.count + index);
    total = total + cost;
  }
  return total;
};

/**
 * Computes the maximum number of adventurers affordable with given gold.
 * @param adventurer - The adventurer type.
 * @param gold - The available gold.
 * @returns The maximum affordable quantity.
 */
const computeMaxAffordable = (adventurer: Adventurer, gold: number): number => {
  let total = 0;
  let quantity = 0;
  for (let index = 0; index < 100_000; index = index + 1) {
    const cost = adventurer.baseCost * Math.pow(1.15, adventurer.count + index);
    if (total + cost > gold) {
      break;
    }
    total = total + cost;
    quantity = quantity + 1;
  }
  return quantity;
};

interface EffectiveAdventurerStats {
  readonly combatPower:      number;
  readonly essencePerSecond: number;
  readonly goldPerSecond:    number;
}

interface AdventurerCardProperties {
  readonly adventurer:     Adventurer;
  readonly currentGold:    number;
  readonly batchSize:      BatchSize;
  readonly unlockHint:     string | undefined;
  readonly formatNumber:   (n: number)=> string;
  readonly effectiveStats: EffectiveAdventurerStats;
}

/**
 * Renders a single adventurer card with buy controls.
 * @param props - The adventurer card properties.
 * @param props.adventurer - The adventurer data.
 * @param props.currentGold - The current gold available.
 * @param props.batchSize - The selected batch size.
 * @param props.unlockHint - Optional quest name that unlocks this adventurer.
 * @param props.formatNumber - The number formatting utility function.
 * @param props.effectiveStats - The post-multiplier per-unit stats.
 * @returns The JSX element.
 */
const AdventurerCard = ({
  adventurer,
  currentGold,
  batchSize,
  unlockHint,
  formatNumber,
  effectiveStats,
}: AdventurerCardProperties): JSX.Element => {
  const { buyAdventurer } = useGame();

  const resolvedQuantity
    = batchSize === "max"
      ? computeMaxAffordable(adventurer, currentGold)
      : batchSize;
  const cost = computeBatchCost(adventurer, resolvedQuantity);
  const canAfford = resolvedQuantity > 0 && currentGold >= cost;

  function handleBuy(): void {
    buyAdventurer(adventurer.id, resolvedQuantity);
  }

  const maxSuffix
    = batchSize === "max" && resolvedQuantity > 0
      ? ` (×${String(resolvedQuantity)})`
      : "";
  const buttonLabel = adventurer.unlocked
    ? `🪙 ${formatNumber(Math.ceil(cost))}${maxSuffix}`
    : "🔒 Locked";

  return (
    <div className={`adventurer-card ${adventurer.unlocked
      ? ""
      : "locked"}`}>
      <img
        alt={adventurer.name}
        className="card-thumbnail"
        src={cdnImage("adventurers", adventurer.id)}
      />
      <div className="adventurer-info">
        <h3>{adventurer.name}</h3>
        <p>
          {formatNumber(effectiveStats.goldPerSecond)}
          {" gold/s each"}
        </p>
        {adventurer.essencePerSecond > 0
          && <p>
            {formatNumber(effectiveStats.essencePerSecond)}
            {" essence/s each"}
          </p>
        }
        <p>
          {formatNumber(effectiveStats.combatPower)}
          {" combat power each"}
        </p>
      </div>
      <div className="adventurer-count">
        {"×"}
        {adventurer.count}
      </div>
      <button
        className="buy-button"
        disabled={!canAfford || !adventurer.unlocked}
        onClick={handleBuy}
        type="button"
      >
        {buttonLabel}
      </button>
      {!adventurer.unlocked && unlockHint !== undefined
        ? <p className="unlock-hint">
          {"📜 Complete: "}
          {unlockHint}
        </p>
        : null}
    </div>
  );
};

/**
 * Renders the adventurer panel with all available adventurers.
 * @returns The JSX element.
 */
const AdventurerPanel = (): JSX.Element => {
  const { state, formatNumber, toggleAutoAdventurer } = useGame();
  const [ showLocked, setShowLocked ] = useState(true);
  const [ batchSize, setBatchSize ] = useState<BatchSize>(() => {
    return parseBatchSize(localStorage.getItem("elysium_batch_size"));
  });

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

  const locked = state.adventurers.filter((adventurer) => {
    return !adventurer.unlocked;
  });
  const visible = showLocked
    ? state.adventurers
    : state.adventurers.filter((adventurer) => {
      return adventurer.unlocked;
    });

  const adventurerUnlockHints = new Map<string, string>();
  for (const quest of state.quests) {
    for (const reward of quest.rewards) {
      if (reward.type === "adventurer" && reward.targetId !== undefined) {
        adventurerUnlockHints.set(reward.targetId, quest.name);
      }
    }
  }

  const autoAdventurerUnlocked = state.prestige.purchasedUpgradeIds.includes(
    "auto_adventurer",
  );
  const autoAdventurerOn = state.autoAdventurer === true;

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

  return (
    <section className="panel adventurer-panel">
      <div className="panel-header">
        <h2>{"Adventurers"}</h2>
        <div className="panel-header-controls">
          {autoAdventurerUnlocked
            ? <button
              className={`auto-toggle-btn ${
                autoAdventurerOn
                  ? "auto-toggle-on"
                  : "auto-toggle-off"
              }`}
              onClick={toggleAutoAdventurer}
              title={
                "Automatically purchase the highest-tier"
                + " affordable adventurer"
              }
              type="button"
            >
              {"🤖 Auto: "}
              {autoAdventurerOn
                ? "ON"
                : "OFF"}
            </button>
            : null
          }
          <LockToggle
            lockedCount={locked.length}
            onToggle={handleToggle}
            showLocked={showLocked}
          />
        </div>
      </div>
      <div className="batch-selector">
        {batchOptions.map((option) => {
          function handleBatchSelect(): void {
            setBatchSize(option);
            localStorage.setItem("elysium_batch_size", String(option));
          }
          return (
            <button
              className={`batch-button ${batchSize === option
                ? "active"
                : ""}`}
              key={option}
              onClick={handleBatchSelect}
              type="button"
            >
              {option === "max"
                ? "xMax"
                : `x${String(option)}`}
            </button>
          );
        })}
      </div>
      <div className="adventurer-list">
        {visible.map((adventurer) => {
          return (
            <AdventurerCard
              adventurer={adventurer}
              batchSize={batchSize}
              currentGold={state.resources.gold}
              effectiveStats={computeEffectiveAdventurerStats(
                state,
                adventurer.id,
              )}
              formatNumber={formatNumber}
              key={adventurer.id}
              unlockHint={adventurerUnlockHints.get(adventurer.id)}
            />
          );
        })}
      </div>
    </section>
  );
};

export { AdventurerPanel };
