import React from "react";

import { sampleContentPack } from "@/data/sampleContentPack";
import { createStartingAdventurer } from "@/rules/character";
import {
  createRunState,
  enterCurrentRoom,
  getAvailableMoves,
  isCurrentRoomCombatReady,
  resolveRunEnemyTurn,
  resolveRunPlayerTurn,
  startCombatInCurrentRoom,
  travelCurrentExit,
} from "@/rules/runState";
import { queueTreasureForSale, sellPendingTreasure, sendTreasureToStash } from "@/rules/town";
import type { RunState } from "@/types/state";

function createDemoRun() {
  const adventurer = createStartingAdventurer(sampleContentPack, {
    name: "Aster",
    weaponId: "weapon.short-sword",
    armourId: "armour.leather-vest",
    scrollId: "scroll.lesser-heal",
  });

  return createRunState({
    content: sampleContentPack,
    campaignId: "campaign.demo",
    adventurer,
  });
}

function getRoomTitle(run: RunState, roomId?: string) {
  if (!roomId) {
    return "Unknown Room";
  }

  const room = run.dungeon.levels[run.currentLevel]?.rooms[roomId];

  if (!room) {
    return "Unknown Room";
  }

  return (
    sampleContentPack.roomTemplates.find((template) => template.id === room.templateId)?.title ??
    room.notes[0] ??
    room.templateId ??
    room.id
  );
}

function getDefinitionName(definitionId: string) {
  const item =
    sampleContentPack.items.find((candidate) => candidate.id === definitionId) ??
    sampleContentPack.weapons.find((candidate) => candidate.id === definitionId) ??
    sampleContentPack.armour.find((candidate) => candidate.id === definitionId) ??
    sampleContentPack.scrolls.find((candidate) => candidate.id === definitionId) ??
    sampleContentPack.potions.find((candidate) => candidate.id === definitionId);

  return item?.name ?? definitionId;
}

function formatInventoryEntry(definitionId: string, quantity: number) {
  const name = getDefinitionName(definitionId);
  return quantity > 1 ? `${quantity}x ${name}` : name;
}

function getTreasureItemIds() {
  return new Set(
    sampleContentPack.items
      .filter((item) => item.itemType === "treasure")
      .map((item) => item.id),
  );
}

function getSupportItemIds() {
  return new Set(
    sampleContentPack.items
      .filter((item) => item.itemType !== "treasure")
      .map((item) => item.id),
  );
}

function getConsumableItemIds() {
  return new Set(
    sampleContentPack.items
      .filter((item) => item.consumable || item.itemType === "ration")
      .map((item) => item.id),
  );
}

const treasureItemIds = getTreasureItemIds();
const supportItemIds = getSupportItemIds();
const consumableItemIds = getConsumableItemIds();

function App() {
  const [run, setRun] = React.useState<RunState>(() => createDemoRun());
  const currentLevel = run.dungeon.levels[run.currentLevel];
  const currentRoom = run.currentRoomId ? currentLevel?.rooms[run.currentRoomId] : undefined;
  const availableMoves = getAvailableMoves(run);
  const combatReadyEncounter = isCurrentRoomCombatReady(run);
  const carriedTreasure = run.adventurerSnapshot.inventory.carried.filter((entry) =>
    treasureItemIds.has(entry.definitionId),
  );
  const carriedConsumables = run.adventurerSnapshot.inventory.carried.filter(
    (entry) =>
      consumableItemIds.has(entry.definitionId) ||
      entry.definitionId.startsWith("potion.") ||
      entry.definitionId.startsWith("scroll."),
  );
  const carriedGear = run.adventurerSnapshot.inventory.carried.filter(
    (entry) =>
      supportItemIds.has(entry.definitionId) &&
      !consumableItemIds.has(entry.definitionId),
  );
  const equippedItems = run.adventurerSnapshot.inventory.equipped;
  const latestLoot = run.lootedItems.slice(-4).reverse();
  const pendingSales = run.townState.pendingSales;
  const stash = run.townState.stash;

  const handleReset = () => {
    setRun(createDemoRun());
  };

  const handleEnterRoom = () => {
    setRun((previous) => enterCurrentRoom({ content: sampleContentPack, run: previous }).run);
  };

  const handleStartCombat = () => {
    setRun((previous) =>
      startCombatInCurrentRoom({ content: sampleContentPack, run: previous }).run,
    );
  };

  const handleTravel = (direction: "north" | "east" | "south" | "west") => {
    setRun((previous) =>
      travelCurrentExit({
        content: sampleContentPack,
        run: previous,
        exitDirection: direction,
      }).run,
    );
  };

  const handlePlayerTurn = (manoeuvreId: string, targetEnemyId: string) => {
    setRun((previous) =>
      resolveRunPlayerTurn({
        content: sampleContentPack,
        run: previous,
        manoeuvreId,
        targetEnemyId,
      }).run,
    );
  };

  const handleEnemyTurn = () => {
    setRun((previous) =>
      resolveRunEnemyTurn({ content: sampleContentPack, run: previous }).run,
    );
  };

  const handleQueueSale = (definitionId: string) => {
    setRun((previous) => queueTreasureForSale(sampleContentPack, previous, definitionId).run);
  };

  const handleStashTreasure = (definitionId: string) => {
    setRun((previous) => sendTreasureToStash(sampleContentPack, previous, definitionId).run);
  };

  const handleSellPending = () => {
    setRun((previous) => sellPendingTreasure(sampleContentPack, previous).run);
  };

  return (
    <main className="app-shell">
      <section className="hero">
        <div>
          <p className="eyebrow">2D6 Dungeon Web</p>
          <h1>Dungeon Loop Shell</h1>
          <p className="lede">
            Traverse generated rooms, auto-resolve room entry, and engage combat
            when a room reveals a real encounter.
          </p>
        </div>

        <div className="hero-actions">
          <button className="button button-primary" onClick={handleReset}>
            Reset Demo Run
          </button>
          <div className="status-chip">
            <span>Run Status</span>
            <strong>{run.status}</strong>
          </div>
        </div>
      </section>

      {combatReadyEncounter && !run.activeCombat ? (
        <section className="alert-banner">
          <div>
            <span className="alert-kicker">Encounter Ready</span>
            <strong>{currentRoom?.encounter?.resultLabel}</strong>
            <p>
              This room contains a combat-ready encounter. Engage now to enter
              tactical resolution.
            </p>
          </div>
          <button className="button button-primary" onClick={handleStartCombat}>
            Engage Encounter
          </button>
        </section>
      ) : null}

      <section className="dashboard-grid">
        <article className="panel panel-highlight">
          <div className="panel-header">
            <h2>Adventurer</h2>
            <span>Level {run.adventurerSnapshot.level}</span>
          </div>
          <div className="stat-strip">
            <div>
              <span>HP</span>
              <strong>
                {run.adventurerSnapshot.hp.current}/{run.adventurerSnapshot.hp.max}
              </strong>
            </div>
            <div>
              <span>Shift</span>
              <strong>{run.adventurerSnapshot.stats.shift}</strong>
            </div>
            <div>
              <span>Discipline</span>
              <strong>{run.adventurerSnapshot.stats.discipline}</strong>
            </div>
            <div>
              <span>Precision</span>
              <strong>{run.adventurerSnapshot.stats.precision}</strong>
            </div>
            <div>
              <span>XP</span>
              <strong>{run.adventurerSnapshot.xp}</strong>
            </div>
          </div>
          <p className="supporting-text">
            {run.adventurerSnapshot.name} is equipped with a{" "}
            {sampleContentPack.weapons.find(
              (weapon) => weapon.id === run.adventurerSnapshot.weaponId,
            )?.name ?? "weapon"}
            .
          </p>
          <p className="supporting-text">
            Run rewards: {run.xpGained} XP, {run.goldGained} gold,{" "}
            {run.defeatedCreatureIds.length} foes defeated.
          </p>
        </article>

        <article className="panel panel-inventory">
          <div className="panel-header">
            <h2>Inventory</h2>
            <span>{run.adventurerSnapshot.inventory.carried.length} carried entries</span>
          </div>
          <div className="inventory-summary">
            <div className="inventory-badge">
              <span>Gold</span>
              <strong>{run.adventurerSnapshot.inventory.currency.gold}</strong>
            </div>
            <div className="inventory-badge">
              <span>Rations</span>
              <strong>{run.adventurerSnapshot.inventory.rationCount}</strong>
            </div>
            <div className="inventory-badge">
              <span>Treasure</span>
              <strong>{carriedTreasure.length}</strong>
            </div>
            <div className="inventory-badge">
              <span>Latest Loot</span>
              <strong>{run.lootedItems.reduce((total, entry) => total + entry.quantity, 0)}</strong>
            </div>
          </div>
          <div className="inventory-grid">
            <section className="inventory-section">
              <span className="inventory-label">Equipped</span>
              <div className="inventory-list">
                {equippedItems.map((entry) => (
                  <article key={`equipped-${entry.definitionId}`} className="inventory-card inventory-card-equipped">
                    <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                    <span>Ready for use</span>
                  </article>
                ))}
              </div>
            </section>
            <section className="inventory-section">
              <span className="inventory-label">Consumables</span>
              <div className="inventory-list">
                {carriedConsumables.length === 0 ? (
                  <p className="supporting-text">No consumables carried.</p>
                ) : (
                  carriedConsumables.map((entry) => (
                    <article key={`consumable-${entry.definitionId}`} className="inventory-card">
                      <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                      <span>Combat or run utility</span>
                    </article>
                  ))
                )}
              </div>
            </section>
            <section className="inventory-section">
              <span className="inventory-label">Pack Gear</span>
              <div className="inventory-list">
                {carriedGear.length === 0 ? (
                  <p className="supporting-text">No general gear carried.</p>
                ) : (
                  carriedGear.map((entry) => (
                    <article key={`gear-${entry.definitionId}`} className="inventory-card">
                      <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                      <span>Travel and exploration kit</span>
                    </article>
                  ))
                )}
              </div>
            </section>
            <section className="inventory-section">
              <span className="inventory-label">Treasure Stash</span>
              <div className="inventory-list">
                {carriedTreasure.length === 0 ? (
                  <p className="supporting-text">No treasure recovered yet.</p>
                ) : (
                  carriedTreasure.map((entry) => (
                    <article key={`treasure-${entry.definitionId}`} className="inventory-card inventory-card-treasure">
                      <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                      <span>Sellable dungeon spoils</span>
                    </article>
                  ))
                )}
              </div>
            </section>
          </div>
          <div className="loot-ribbon">
            <span className="inventory-label">Recent Spoils</span>
            {latestLoot.length === 0 ? (
              <p className="supporting-text">Win a fight to populate the loot ribbon.</p>
            ) : (
              <div className="loot-ribbon-list">
                {latestLoot.map((entry) => (
                  <article key={`recent-${entry.definitionId}`} className="loot-pill">
                    <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                  </article>
                ))}
              </div>
            )}
          </div>
        </article>

        <article className="panel panel-town">
          <div className="panel-header">
            <h2>Town Market</h2>
            <span>{run.townState.visits} town actions</span>
          </div>
          <div className="town-summary">
            <div className="inventory-badge">
              <span>Known Services</span>
              <strong>{run.townState.knownServices.length}</strong>
            </div>
            <div className="inventory-badge">
              <span>Queued Sales</span>
              <strong>{pendingSales.length}</strong>
            </div>
            <div className="inventory-badge">
              <span>Stash</span>
              <strong>{stash.length}</strong>
            </div>
          </div>
          <div className="town-actions">
            <button
              className="button button-primary"
              onClick={handleSellPending}
              disabled={pendingSales.length === 0}
            >
              Sell Queued Treasure
            </button>
          </div>
          <section className="town-section">
            <span className="inventory-label">Treasure In Pack</span>
            <div className="inventory-list">
              {carriedTreasure.length === 0 ? (
                <p className="supporting-text">No treasure available for town actions.</p>
              ) : (
                carriedTreasure.map((entry) => (
                  <article key={`town-pack-${entry.definitionId}`} className="town-card">
                    <div>
                      <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                      <span>Choose whether to sell or stash this treasure.</span>
                    </div>
                    <div className="enemy-actions">
                      <button className="button" onClick={() => handleStashTreasure(entry.definitionId)}>
                        Send To Stash
                      </button>
                      <button className="button button-primary" onClick={() => handleQueueSale(entry.definitionId)}>
                        Queue For Sale
                      </button>
                    </div>
                  </article>
                ))
              )}
            </div>
          </section>
          <section className="town-section">
            <span className="inventory-label">Pending Sales</span>
            <div className="inventory-list">
              {pendingSales.length === 0 ? (
                <p className="supporting-text">Nothing queued at the market.</p>
              ) : (
                pendingSales.map((entry) => (
                  <article key={`pending-${entry.definitionId}`} className="inventory-card inventory-card-treasure">
                    <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                    <span>Ready to convert into gold</span>
                  </article>
                ))
              )}
            </div>
          </section>
          <section className="town-section">
            <span className="inventory-label">Town Stash</span>
            <div className="inventory-list">
              {stash.length === 0 ? (
                <p className="supporting-text">The stash is empty.</p>
              ) : (
                stash.map((entry) => (
                  <article key={`stash-${entry.definitionId}`} className="inventory-card">
                    <strong>{formatInventoryEntry(entry.definitionId, entry.quantity)}</strong>
                    <span>Held safely in town storage</span>
                  </article>
                ))
              )}
            </div>
          </section>
        </article>

        <article className="panel">
          <div className="panel-header">
            <h2>Current Room</h2>
            <span>Level {run.currentLevel}</span>
          </div>
          <h3 className="room-title">
            {getRoomTitle(run, run.currentRoomId)}
          </h3>
          <p className="supporting-text">
            {currentRoom?.notes[1] ?? "No encounter notes available yet."}
          </p>
          <div className="room-meta">
            <span>Entered: {currentRoom?.discovery.entered ? "Yes" : "No"}</span>
            <span>Cleared: {currentRoom?.discovery.cleared ? "Yes" : "No"}</span>
            <span>Exits: {currentRoom?.exits.length ?? 0}</span>
          </div>
          <div className="button-row">
            <button className="button" onClick={handleEnterRoom}>
              Enter Room
            </button>
            <button
              className="button button-primary"
              onClick={handleStartCombat}
              disabled={!combatReadyEncounter || Boolean(run.activeCombat)}
            >
              Start Combat
            </button>
          </div>
          <div className="encounter-box">
            <span className="encounter-label">Encounter</span>
            <strong>{currentRoom?.encounter?.resultLabel ?? "None"}</strong>
          </div>
        </article>

        <article className="panel">
          <div className="panel-header">
            <h2>Navigation</h2>
            <span>{availableMoves.length} exits</span>
          </div>
          <div className="move-list">
            {availableMoves.map((move) => (
              <button
                key={move.direction}
                className="move-card"
                onClick={() => handleTravel(move.direction)}
                disabled={Boolean(run.activeCombat)}
              >
                <span>{move.direction}</span>
                <strong>{move.leadsToRoomId ? "Travel" : "Generate"}</strong>
                <em>
                  {move.leadsToRoomId
                    ? getRoomTitle(run, move.leadsToRoomId)
                    : `${move.exitType} exit`}
                </em>
              </button>
            ))}
          </div>
          <div className="mini-map">
            {currentLevel?.discoveredRoomOrder.map((roomId) => {
              const room = currentLevel.rooms[roomId];
              const active = roomId === run.currentRoomId;

              return (
                <article
                  key={roomId}
                  className={`map-node${active ? " map-node-active" : ""}`}
                >
                  <span>
                    {room.position.x},{room.position.y}
                  </span>
                  <strong>{getRoomTitle(run, roomId)}</strong>
                </article>
              );
            })}
          </div>
        </article>

        <article className="panel">
          <div className="panel-header">
            <h2>Combat</h2>
            <span>{run.activeCombat ? `Round ${run.activeCombat.round}` : "Inactive"}</span>
          </div>
          {run.activeCombat ? (
            <>
              <div className="combat-status">
                <span>Acting Side</span>
                <strong>{run.activeCombat.actingSide}</strong>
              </div>
              <div className="enemy-list">
                {run.activeCombat.enemies.map((enemy) => (
                  <div key={enemy.id} className="enemy-card">
                    <div>
                      <strong>{enemy.name}</strong>
                      <span>
                        HP {enemy.hpCurrent}/{enemy.hpMax}
                      </span>
                    </div>
                    <div className="enemy-actions">
                      <button
                        className="button"
                        onClick={() =>
                          handlePlayerTurn("manoeuvre.exact-strike", enemy.id)
                        }
                        disabled={
                          run.activeCombat?.actingSide !== "player" ||
                          enemy.hpCurrent <= 0
                        }
                      >
                        Exact Strike
                      </button>
                      <button
                        className="button"
                        onClick={() => handlePlayerTurn("manoeuvre.guard-break", enemy.id)}
                        disabled={
                          run.activeCombat?.actingSide !== "player" ||
                          enemy.hpCurrent <= 0
                        }
                      >
                        Guard Break
                      </button>
                    </div>
                  </div>
                ))}
              </div>
              <div className="button-row">
                <button
                  className="button button-primary"
                  onClick={handleEnemyTurn}
                  disabled={run.activeCombat.actingSide !== "enemy"}
                >
                  Resolve Enemy Turn
                </button>
              </div>
            </>
          ) : (
            <p className="supporting-text">
              No active combat. Travel until a room reveals a hostile encounter,
              then engage it from the banner or room panel.
            </p>
          )}
        </article>

        <article className="panel panel-log">
          <div className="panel-header">
            <h2>Run Log</h2>
            <span>{run.log.length} entries</span>
          </div>
          <div className="log-list">
            {run.log.length === 0 ? (
              <p className="supporting-text">No events recorded yet.</p>
            ) : (
              run.log
                .slice()
                .reverse()
                .map((entry) => (
                  <article key={entry.id} className="log-entry">
                    <span>{entry.type}</span>
                    <p>{entry.text}</p>
                  </article>
                ))
            )}
          </div>
        </article>
      </section>
    </main>
  );
}

export default App;
