import { lazy, Suspense, useCallback, useEffect, useRef } from "react";
import packageJson from "../package.json";
import { DualDisplayFrame } from "./components/DualDisplayFrame";
import { FrontEnd } from "./components/FrontEnd";
import { useActiveHunter, useFrontendStore } from "./frontend/store";
import { useGameStore } from "./game/store";
import type { BossId } from "./game/types";
import type { DifficultySlug } from "./game/progression/loot";
import { useActionBindings } from "./game/useGameLoop";
import { useAuthoritativeDualScreenSync, useForcedThorDisplays } from "./platform/useThorDualScreen";
import { DUAL_SCREEN_EXIT_EVENT, DUAL_SCREEN_LAUNCH_EVENT } from "./platform/dualScreenSync";

const TopScreen = lazy(() => import("./components/TopScreen").then((module) => ({ default: module.TopScreen })));
const BottomScreen = lazy(() => import("./components/BottomScreen").then((module) => ({ default: module.BottomScreen })));

function GameLoadingScreen() {
  return (
    <DualDisplayFrame
      top={<section className="display top-display game-loading"><span>✦</span><strong>Opening the Ember Vault</strong><small>Preparing world and party…</small></section>}
      bottom={<section className="display bottom-display game-loading is-lower"><span>IH</span><strong>Loading field console</strong><small>Offline save secured</small></section>}
    />
  );
}

export default function App() {
  useForcedThorDisplays();
  useAuthoritativeDualScreenSync();
  const screen = useFrontendStore((state) => state.screen);
  const hunter = useActiveHunter();
  const settings = useFrontendStore((state) => state.settings);
  const navigate = useFrontendStore((state) => state.navigate);
  const touchActiveSave = useFrontendStore((state) => state.touchActiveSave);
  const updateActiveHealerInventory = useFrontendStore((state) => state.updateActiveHealerInventory);
  const recordBossVictory = useFrontendStore((state) => state.recordBossVictory);
  const recordRoguelikeDefeat = useFrontendStore((state) => state.recordRoguelikeDefeat);
  const recordRogueTrialsEndlessDefeat = useFrontendStore((state) => state.recordRogueTrialsEndlessDefeat);
  const clearRecentRewards = useFrontendStore((state) => state.clearRecentRewards);
  const rewardedBossInstances = useRef(new Set<string>());
  const screenRef = useRef(screen);
  screenRef.current = screen;
  const leaveGame = useCallback(() => {
    const { accountId, activeSlotId, uploadSlot } = useFrontendStore.getState();
    updateActiveHealerInventory(useGameStore.getState().inventory);
    touchActiveSave();
    navigate("home");
    if (accountId && activeSlotId) void uploadSlot(activeSlotId);
  }, [navigate, touchActiveSave, updateActiveHealerInventory]);
  const launchGame = useCallback((bossIds: readonly BossId[], requestedDifficultySlug?: DifficultySlug) => {
    if (!hunter) return;
    const progress = hunter.healers[hunter.activeClassId];
    const selectedMode = useFrontendStore.getState().selectedMode;
    const runMode = selectedMode === "roguelike-pve" ? "roguelike" : selectedMode === "rogue-trials" ? "rogue-trials" : "encounter";
    const launchDifficulty = runMode !== "encounter"
      ? "initiate"
      : requestedDifficultySlug ?? useFrontendStore.getState().selectedDifficultySlug;
    rewardedBossInstances.current.clear();
    clearRecentRewards();
    useGameStore.getState().configureHealer(hunter.activeClassId, hunter.hunterName, progress.inventory, bossIds, runMode, hunter.gearProgress, launchDifficulty);
    touchActiveSave();
    navigate("game");
  }, [clearRecentRewards, hunter, navigate, touchActiveSave]);

  useEffect(() => {
    const onDualScreenLaunch = (event: Event) => {
      const detail = (event as CustomEvent<{ bossIds: readonly BossId[]; difficultySlug?: DifficultySlug } | readonly BossId[]>).detail;
      if ("bossIds" in detail) launchGame(detail.bossIds, detail.difficultySlug);
      else launchGame(detail);
    };
    window.addEventListener(DUAL_SCREEN_LAUNCH_EVENT, onDualScreenLaunch);
    return () => window.removeEventListener(DUAL_SCREEN_LAUNCH_EVENT, onDualScreenLaunch);
  }, [launchGame]);

  useEffect(() => {
    window.addEventListener(DUAL_SCREEN_EXIT_EVENT, leaveGame);
    return () => window.removeEventListener(DUAL_SCREEN_EXIT_EVENT, leaveGame);
  }, [leaveGame]);

  useActionBindings(screen === "game", leaveGame);

  useEffect(() => {
    document.documentElement.classList.toggle("large-interface-text", settings.largeText);
    document.documentElement.classList.toggle("force-reduced-motion", settings.reducedMotion);
  }, [settings.largeText, settings.reducedMotion]);

  useEffect(() => {
    return useGameStore.subscribe((state, previousState) => {
      const startedFreshEncounter = state.phase === "briefing" && previousState.phase !== "briefing"
        || previousState.phase === "intermission" && state.phase === "combat"
        || previousState.phase === "victory" && state.phase === "combat" && state.endlessMode;
      if (state.phase === "briefing"
        || previousState.phase === "intermission" && state.phase === "combat"
        || previousState.phase === "victory" && state.phase === "combat" && state.endlessMode) {
        rewardedBossInstances.current.clear();
      }
      if (startedFreshEncounter) clearRecentRewards();
      if (screenRef.current !== "game") return;
      if (state.runMode === "roguelike" && state.phase === "defeat" && previousState.phase !== "defeat") {
        recordRoguelikeDefeat(state.round);
      }
      if (state.endlessMode && state.phase === "defeat" && previousState.phase !== "defeat") {
        recordRogueTrialsEndlessDefeat(state.endlessBossKills);
      }
      const bossCount = 1 + state.additionalBosses.length;
      if (state.boss.hp <= 0 && previousState.boss.hp > 0) {
        const primaryInstanceId = state.bossInstanceId;
        if (!rewardedBossInstances.current.has(primaryInstanceId)) {
          if (!state.endlessMode) rewardedBossInstances.current.add(primaryInstanceId);
          const defeatedBefore = (state.round - 1) * bossCount;
          const rewardDifficulty = state.runMode !== "encounter" && defeatedBefore >= 5 ? "veteran" : state.difficultySlug;
          recordBossVictory(state.boss.id, rewardDifficulty);
        }
      }
      for (let index = 0; index < state.additionalBosses.length; index += 1) {
        const entry = state.additionalBosses[index];
        const previous = previousState.additionalBosses[index];
        const justDefeated = entry.boss.hp <= 0 && (!previous || previous.instanceId !== entry.instanceId || previous.boss.hp > 0);
        if (!justDefeated || !state.endlessMode && rewardedBossInstances.current.has(entry.instanceId)) continue;
        if (!state.endlessMode) rewardedBossInstances.current.add(entry.instanceId);
        const defeatedBefore = (state.round - 1) * bossCount + index + 1;
        const rewardDifficulty = state.runMode !== "encounter" && defeatedBefore >= 5 ? "veteran" : state.difficultySlug;
        recordBossVictory(entry.boss.id, rewardDifficulty);
      }
    });
  }, [clearRecentRewards, recordBossVictory, recordRoguelikeDefeat, recordRogueTrialsEndlessDefeat]);

  return (
    <main className="app-shell">
      <header className="app-header">
        <div><span>THOR / DUAL DISPLAY</span><strong>I Want To Heal</strong></div>
        <p>Offline-first healer roguelike <i /> v{packageJson.version}</p>
      </header>
      {screen === "game"
        ? <Suspense fallback={<GameLoadingScreen />}><DualDisplayFrame top={<TopScreen onExit={leaveGame} />} bottom={<BottomScreen onExit={leaveGame} />} /></Suspense>
        : <FrontEnd onLaunch={launchGame} />}
    </main>
  );
}
