/**
 * @file Codex panel component displaying discovered lore entries.
 * @copyright nhcarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */
/* eslint-disable max-lines-per-function -- Complex component with zone and entry rendering */
import { type JSX, useState } from "react";
import { useGame } from "../../context/gameContext.js";
import { CODEX_ENTRIES, ZONE_LABELS } from "../../data/codex.js";
import { cdnImage } from "../../utils/cdn.js";
import type { CodexEntry } from "@elysium/types";

/**
 * Converts a fraction to a percentage value.
 * @param numerator - The numerator value.
 * @param denominator - The denominator value.
 * @returns The percentage as a number between 0 and 100.
 */
const toPercent = (numerator: number, denominator: number): number => {
  if (denominator === 0) {
    return 0;
  }
  const scaled = numerator * 100;
  return scaled / denominator;
};

const sourceBadge: Record<CodexEntry["sourceType"], string> = {
  adventurer:  "👥",
  boss:        "⚔️",
  equipment:   "🛡️",
  exploration: "🧭",
  prestige:    "🔮",
  quest:       "📜",
  recipe:      "⚗️",
  upgrade:     "🔧",
  zone:        "🗺️",
};

const sourceTypeFolder: Record<CodexEntry["sourceType"], string> = {
  adventurer:  "adventurers",
  boss:        "bosses",
  equipment:   "equipment",
  exploration: "explorations",
  prestige:    "prestige-upgrades",
  quest:       "quests",
  recipe:      "recipes",
  upgrade:     "upgrades",
  zone:        "zones",
};

/**
 * Converts a snake_case ID to a Title Case display name.
 * @param id - The snake_case identifier to format.
 * @returns The formatted display name.
 */
const formatId = (id: string): string => {
  return id.split("_").
    map((word) => {
      return word.charAt(0).toUpperCase() + word.slice(1);
    }).
    join(" ");
};

/**
 * Generates a human-readable unlock hint for a locked codex entry.
 * @param entry - The locked codex entry.
 * @returns A string describing how to unlock the entry.
 */
const buildUnlockHint = (entry: CodexEntry): string => {
  const name = formatId(entry.sourceId);
  switch (entry.sourceType) {
    case "boss": return `Defeat ${name}`;
    case "quest": return `Complete: ${name}`;
    case "equipment": return `Obtain: ${name}`;
    case "adventurer": return `Recruit a ${name}`;
    case "upgrade": return `Purchase: ${name}`;
    case "prestige": return `Purchase runestone upgrade: ${name}`;
    case "zone": return `Explore: ${name}`;
    case "exploration": return `Discover: ${name}`;
    case "recipe": return `Craft: ${name}`;
    default: return "Keep playing to unlock";
  }
};

/**
 * Renders the codex panel with lore entries grouped by zone.
 * @returns The JSX element.
 */
const CodexPanel = (): JSX.Element => {
  const { state } = useGame();
  const [ expandedId, setExpandedId ] = useState<string | null>(null);

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

  const unlockedIds = new Set(state.codex?.unlockedEntryIds ?? []);
  const totalEntries = CODEX_ENTRIES.length;
  const unlockedCount = CODEX_ENTRIES.filter((entry) => {
    return unlockedIds.has(entry.id);
  }).length;
  const progressPercent = toPercent(unlockedCount, totalEntries);

  const entriesByZone = Object.entries(ZONE_LABELS).
    map(([ zoneId, zoneName ]) => {
      const entries = CODEX_ENTRIES.filter((entry) => {
        return entry.zoneId === zoneId;
      });
      const unlockedEntries = entries.filter((entry) => {
        return unlockedIds.has(entry.id);
      });
      return {
        entries,
        unlockedEntries,
        zoneId,
        zoneName,
      };
    }).
    filter(({ entries }) => {
      return entries.length > 0;
    });

  return (
    <section className="panel codex-panel">
      <h2>{"📖 Codex"}</h2>

      <div className="codex-progress">
        <p className="codex-progress-text">
          {"Lore discovered: "}
          <strong>
            {unlockedCount}
            {" / "}
            {totalEntries}
          </strong>
        </p>
        <div className="codex-progress-bar">
          <div
            className="codex-progress-fill"
            style={{ width: `${String(Math.round(progressPercent))}%` }}
          />
        </div>
      </div>

      {entriesByZone.map(({ zoneId, zoneName, entries, unlockedEntries }) => {
        return (
          <div className="codex-zone" key={zoneId}>
            <h3 className="codex-zone-header">
              {zoneName}
              <span className="codex-zone-count">
                {unlockedEntries.length}
                {"/"}
                {entries.length}
              </span>
            </h3>

            <div className="codex-entries">
              {entries.map((entry) => {
                const isUnlocked = unlockedIds.has(entry.id);
                const isExpanded = expandedId === entry.id;

                if (!isUnlocked) {
                  return (
                    <div className="codex-entry locked" key={entry.id}>
                      <div className="codex-entry-header">
                        <span className="codex-lock">{"🔒"}</span>
                        <span className="codex-entry-title">{"???"}</span>
                      </div>
                      <p className="codex-unlock-hint">
                        {buildUnlockHint(entry)}
                      </p>
                    </div>
                  );
                }

                function handleExpand(): void {
                  setExpandedId(isExpanded
                    ? null
                    : entry.id);
                }

                return (
                  <div
                    className={`codex-entry unlocked ${
                      isExpanded
                        ? "expanded"
                        : ""
                    }`}
                    key={entry.id}
                    onClick={handleExpand}
                  >
                    <div className="codex-entry-header">
                      <span className="codex-source-badge">
                        {sourceBadge[entry.sourceType]}
                      </span>
                      <span className="codex-entry-title">{entry.title}</span>
                      <span className="codex-chevron">
                        {isExpanded
                          ? "▲"
                          : "▼"}
                      </span>
                    </div>
                    {isExpanded
                      ? <>
                        <img
                          alt={entry.title}
                          className="codex-entry-image"
                          src={cdnImage(
                            sourceTypeFolder[entry.sourceType],
                            entry.sourceId,
                          )}
                        />
                        <p className="codex-entry-content">{entry.content}</p>
                      </>
                      : null}
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </section>
  );
};

export { CodexPanel };
