/**
 * @file Quest panel component for managing and completing quests.
 * @copyright nhcarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */
/* eslint-disable react/no-multi-comp -- QuestCard sub-component is tightly coupled */
/* eslint-disable max-lines-per-function -- Complex component with many render paths */
/* eslint-disable complexity -- Many conditional render paths */
/* eslint-disable max-statements -- Many local variables needed for quest state */
import { useState, type JSX } 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 { Quest } from "@elysium/types";

/**
 * Formats a duration in seconds to a human-readable string.
 * @param seconds - The total number of seconds to format.
 * @returns The formatted duration string.
 */
const formatDuration = (seconds: number): string => {
  const secondsPerHour = 3600;
  const secondsPerMinute = 60;
  if (seconds >= secondsPerHour) {
    const hours = Math.floor(seconds / secondsPerHour);
    const remainderSeconds = seconds % secondsPerHour;
    const minutes = Math.floor(remainderSeconds / secondsPerMinute);
    return `${String(hours)}h ${String(minutes)}m`;
  }
  if (seconds >= secondsPerMinute) {
    const minutes = Math.floor(seconds / secondsPerMinute);
    const secs = seconds % secondsPerMinute;
    return `${String(minutes)}m ${String(secs)}s`;
  }
  return `${String(seconds)}s`;
};

/**
 * Computes the time remaining for an active quest.
 * @param quest - The quest to check.
 * @returns The remaining seconds.
 */
const questTimeRemaining = (quest: Quest): number => {
  if (quest.status !== "active" || quest.startedAt === undefined) {
    return 0;
  }
  const elapsed = (Date.now() - quest.startedAt) / 1000;
  return Math.max(0, quest.durationSeconds - elapsed);
};

interface QuestCardProperties {
  readonly quest:            Quest;
  readonly partyCombatPower: number;
  readonly unlockHint:       string | undefined;
  readonly zoneHint:         string | undefined;
}

/**
 * Renders a single quest card.
 * @param props - The quest card properties.
 * @param props.quest - The quest to display.
 * @param props.partyCombatPower - The current party's combat power.
 * @param props.unlockHint - Optional hint for how to unlock this quest.
 * @param props.zoneHint - Optional hint for which zone to unlock.
 * @returns The JSX element.
 */
const QuestCard = ({
  quest,
  partyCombatPower,
  unlockHint,
  zoneHint,
}: QuestCardProperties): JSX.Element => {
  const { startQuest, formatNumber } = useGame();
  const cpRequired = quest.combatPowerRequired ?? 0;
  const meetsCP = partyCombatPower >= cpRequired;

  function handleStartQuest(): void {
    startQuest(quest.id);
  }

  return (
    <div className={`quest-card quest-${quest.status}`}>
      <img
        alt={quest.name}
        className="card-thumbnail"
        src={cdnImage("quests", quest.id)}
      />
      <div className="quest-info">
        <h3>{quest.name}</h3>
        <p>{quest.description}</p>
        {cpRequired > 0
          && <p
            className={`quest-cp-requirement ${
              meetsCP
                ? "cp-met"
                : "cp-unmet"
            }`}
          >
            {"⚔️ Requires "}
            {formatNumber(cpRequired)}
            {" Combat Power"}
            {quest.status === "available"
              && (meetsCP
                ? " ✓"
                : ` (you have ${formatNumber(partyCombatPower)})`)}
          </p>
        }
        <div className="quest-rewards">
          {quest.rewards.map((reward) => {
            return (
              <span className="reward-tag" key={`${reward.type}-${String(reward.amount ?? "")}`}>
                {reward.type === "gold"
                  && `🪙 ${formatNumber(reward.amount ?? 0)}`}
                {reward.type === "essence"
                  && `✨ ${formatNumber(reward.amount ?? 0)}`}
                {reward.type === "crystals"
                  && `💎 ${formatNumber(reward.amount ?? 0)}`}
                {reward.type === "upgrade" && "🔓 Upgrade"}
                {reward.type === "adventurer" && "👥 New Adventurer"}
              </span>
            );
          })}
        </div>
      </div>
      <div className="quest-action">
        {quest.status === "locked"
          && <>
            <span className="quest-badge locked">{"🔒 Locked"}</span>
            {zoneHint === undefined
              ? null
              : <p className="unlock-hint">
                {"🗺️ Unlock zone: "}
                {zoneHint}
              </p>
            }
            {zoneHint === undefined && unlockHint !== undefined
              ? <p className="unlock-hint">
                {"📜 Complete: "}
                {unlockHint}
              </p>
              : null}
          </>
        }
        {quest.status === "available" && quest.lastFailedAt !== undefined
          && <p className="quest-failed-hint">{"⚠️ Last attempt failed"}</p>
        }
        {quest.status === "available"
          && <button
            className="start-quest-button"
            disabled={!meetsCP}
            onClick={handleStartQuest}
            title={
              meetsCP
                ? undefined
                : `Need ${formatNumber(cpRequired)} combat power`
            }
            type="button"
          >
            {"Send Party ("}
            {formatDuration(quest.durationSeconds)}
            {")"}
          </button>
        }
        {quest.status === "active"
          && <span className="quest-badge active">
            {"⏳ "}
            {formatDuration(Math.ceil(questTimeRemaining(quest)))}
            {" remaining"}
          </span>
        }
        {quest.status === "completed"
          && <span className="quest-badge completed">{"✅ Complete"}</span>
        }
      </div>
    </div>
  );
};

/**
 * Renders the quest panel with zone selection and quest list.
 * @returns The JSX element.
 */
const QuestPanel = (): JSX.Element => {
  const { state, toggleAutoQuest } = useGame();
  const [ activeZoneId, setActiveZoneId ] = useState("verdant_vale");
  const [ showLocked, setShowLocked ] = useState(true);

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

  const { adventurers, autoQuest, quests, zones } = state;
  let partyCombatPower = 0;
  for (const adventurer of adventurers) {
    const contribution = adventurer.combatPower * adventurer.count;
    partyCombatPower = partyCombatPower + contribution;
  }
  const zoneQuests = quests.filter(({ zoneId }) => {
    return zoneId === activeZoneId;
  });
  const lockedCount = zoneQuests.filter(({ status }) => {
    return status === "locked";
  }).length;
  const visibleQuests = showLocked
    ? zoneQuests
    : zoneQuests.filter(({ status }) => {
      return status !== "locked";
    });

  const questNameById = new Map(
    quests.map(({ id, name }) => {
      return [ id, name ];
    }),
  );
  const zoneById = new Map(
    zones.map((zone) => {
      return [ zone.id, zone ];
    }),
  );
  const questUnlockHints = new Map<string, string>();
  const questZoneHints = new Map<string, string>();
  for (const { id: questId, status, zoneId, prerequisiteIds } of quests) {
    if (status !== "locked") {
      continue;
    }
    const zone = zoneById.get(zoneId);
    if (zone?.status === "locked") {
      questZoneHints.set(questId, zone.name);
    } else if (prerequisiteIds.length > 0) {
      const [ prereqId ] = prerequisiteIds;
      if (prereqId !== undefined) {
        const prereqName = questNameById.get(prereqId);
        if (prereqName !== undefined) {
          questUnlockHints.set(questId, prereqName);
        }
      }
    }
  }

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

  function handleAutoQuest(): void {
    toggleAutoQuest();
  }

  const autoQuestOn = autoQuest === true;

  return (
    <section className="panel quest-panel">
      <div className="panel-header">
        <h2>{"Quests"}</h2>
        <div className="panel-header-controls">
          <button
            className={`auto-toggle-btn ${
              autoQuestOn
                ? "auto-toggle-on"
                : "auto-toggle-off"
            }`}
            onClick={handleAutoQuest}
            title="Automatically send the party on the highest available quest"
            type="button"
          >
            {"🤖 Auto: "}
            {autoQuestOn
              ? "ON"
              : "OFF"}
          </button>
          <LockToggle
            lockedCount={lockedCount}
            onToggle={handleToggle}
            showLocked={showLocked}
          />
        </div>
      </div>

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

      <div className="quest-list">
        {visibleQuests.map((quest) => {
          return (
            <QuestCard
              key={quest.id}
              partyCombatPower={partyCombatPower}
              quest={quest}
              unlockHint={questUnlockHints.get(quest.id)}
              zoneHint={questZoneHints.get(quest.id)}
            />
          );
        })}
        {visibleQuests.length === 0
          && <p className="empty-zone">{"No quests to show in this zone."}</p>
        }
      </div>
    </section>
  );
};

export { QuestPanel };
