import {useCallback, useEffect, useMemo, useState} from 'react';

import {getLiveGamePlayTimeMs} from '../../data/runtimeStats';
import {getWorldCampScenePreset} from '../../data/scenePresets';
import type {StoryOption} from '../../types';
import {UI_CHROME} from '../../uiAssets';
import {GameShellCanvasStage} from './GameShellCanvasStage';
import {GameShellMainContent} from './GameShellMainContent';
import {GameShellOverlays} from './GameShellOverlays';
import {type GameShellProps} from './types';
import {useGameShellViewModel} from './useGameShellViewModel';
import {SCENE_TRANSITION_FUNCTION_MODES, useSceneTransitionModel} from './useSceneTransitionModel';

export function GameShellRuntime({session, story, entry, companions, audio}: GameShellProps) {
  const {
    gameState,
    currentStory,
    isLoading,
    aiError,
    bottomTab,
    setBottomTab,
    isMapOpen,
    setIsMapOpen,
  } = session;
  const {
    displayedOptions,
    canRefreshOptions,
    handleRefreshOptions,
    handleChoice,
    handleMapTravelToScene,
    npcUi,
    characterChatUi,
    inventoryUi,
    battleRewardUi,
    questUi,
  } = story;
  const {
    hasSavedGame,
    handleContinueGame,
    handleStartNewGame,
    handleSaveAndExit,
    handleWorldSelect,
    handleBackToWorldSelect,
    handleCharacterSelect,
  } = entry;
  const {companionRenderStates, onBenchCompanion, onActivateRosterCompanion} = companions;
  const {musicVolume, onMusicVolumeChange} = audio;

  const [clockNow, setClockNow] = useState(() => Date.now());
  const openingCampSceneId = useMemo(
    () => (gameState.worldType ? getWorldCampScenePreset(gameState.worldType)?.id ?? null : null),
    [gameState.worldType],
  );
  const hasNpcModalOpen = Boolean(npcUi.tradeModal || npcUi.giftModal || npcUi.recruitModal);
  const {
    selectionStage,
    setSelectionStage,
    overlayPanel,
    openOverlayPanel,
    closeOverlayPanel,
    selectedSceneEntity,
    setSelectedSceneEntity,
    openPartyMemberDetails,
    closeAdventureEntityModal,
    showTeamModal,
    openCampModal,
    closeCampModal,
    resetForSaveAndExit,
    shouldMountAdventureEntityModal,
    shouldMountCampModal,
    shouldMountMapModal,
    shouldMountCharacterChatModal,
    shouldMountNpcModals,
  } = useGameShellViewModel({
    gameState,
    isMapOpen,
    characterChatModalOpen: Boolean(characterChatUi.modal),
    hasNpcModalOpen,
  });
  const {
    visibleGameState,
    visibleCurrentStory,
    sceneTransitionPhase,
    sceneTransitionToken,
    setSceneTransitionDurations,
    beginSceneTransition,
  } = useSceneTransitionModel({
    gameState,
    currentStory,
    openingCampSceneId,
  });
  const isCharacterSelectionStage =
    gameState.currentScene === 'Selection' &&
    Boolean(gameState.worldType) &&
    !gameState.playerCharacter;
  const shouldHideStoryOptions = sceneTransitionPhase !== 'idle';
  const hideSelectionHero =
    gameState.currentScene === 'Selection' &&
    selectionStage !== 'start';

  const dialogueIndicator = useMemo(() => {
    if (!isLoading || visibleCurrentStory?.displayMode !== 'dialogue' || visibleGameState.currentEncounter?.kind !== 'npc') {
      return null;
    }

    const lastSpeaker = visibleCurrentStory.dialogue?.[visibleCurrentStory.dialogue.length - 1]?.speaker ?? null;
    return {
      showPlayer: true,
      showEncounter: true,
      activeSpeaker: lastSpeaker === 'player' ? 'player' : lastSpeaker ? 'npc' : null,
    } as const;
  }, [visibleCurrentStory?.dialogue, visibleCurrentStory?.displayMode, visibleGameState.currentEncounter?.kind, isLoading]);

  const characterChatSummaries = useMemo(
    () =>
      Object.fromEntries(
        Object.entries(gameState.characterChats ?? {}).map(([characterId, record]) => [characterId, record.summary]),
      ),
    [gameState.characterChats],
  );

  const canvasCompanionRenderStates = useMemo(() => {
    const activeEncounterNpcId = visibleGameState.currentEncounter?.kind === 'npc'
      ? visibleGameState.currentEncounter.id ?? null
      : null;
    if (!activeEncounterNpcId) return companionRenderStates;
    return companionRenderStates.filter(companion => companion.npcId !== activeEncounterNpcId);
  }, [companionRenderStates, visibleGameState.currentEncounter]);

  const livePlayTimeMs = useMemo(
    () => getLiveGamePlayTimeMs(gameState.runtimeStats, clockNow),
    [clockNow, gameState.runtimeStats],
  );

  const adventureStatistics = useMemo(
    () => ({
      playTimeMs: livePlayTimeMs,
      hostileNpcsDefeated: gameState.runtimeStats.hostileNpcsDefeated,
      questsAccepted: gameState.runtimeStats.questsAccepted,
      questsCompleted: visibleGameState.quests.filter(quest => quest.status === 'completed' || quest.status === 'turned_in').length,
      questsTurnedIn: visibleGameState.quests.filter(quest => quest.status === 'turned_in').length,
      itemsUsed: gameState.runtimeStats.itemsUsed,
      scenesTraveled: gameState.runtimeStats.scenesTraveled,
      currentSceneName: visibleGameState.currentScenePreset?.name ?? '当前区域',
      playerCurrency: visibleGameState.playerCurrency,
      inventoryItemCount: visibleGameState.playerInventory.reduce((sum, item) => sum + item.quantity, 0),
      inventoryStackCount: visibleGameState.playerInventory.length,
      activeCompanionCount: visibleGameState.companions.length,
      rosterCompanionCount: visibleGameState.roster.length,
    }),
    [
      gameState.runtimeStats.itemsUsed,
      gameState.runtimeStats.hostileNpcsDefeated,
      gameState.runtimeStats.questsAccepted,
      gameState.runtimeStats.scenesTraveled,
      livePlayTimeMs,
      visibleGameState.companions.length,
      visibleGameState.currentScenePreset?.name,
      visibleGameState.playerCurrency,
      visibleGameState.playerInventory,
      visibleGameState.quests,
      visibleGameState.roster.length,
    ],
  );

  useEffect(() => {
    if (!gameState.playerCharacter || gameState.currentScene !== 'Story') {
      return;
    }

    setClockNow(Date.now());
    const intervalId = window.setInterval(() => setClockNow(Date.now()), 1000);
    return () => window.clearInterval(intervalId);
  }, [gameState.currentScene, gameState.playerCharacter]);

  const handleSceneTransitionChoice = useCallback((option: StoryOption) => {
    const transitionMode = SCENE_TRANSITION_FUNCTION_MODES[option.functionId];
    if (transitionMode) {
      beginSceneTransition(transitionMode);
    }
    handleChoice(option);
  }, [beginSceneTransition, handleChoice]);

  return (
    <div
      className="fusion-pixel-app pixel-root-shell flex h-screen max-h-screen flex-col overflow-hidden font-sans text-zinc-100"
      style={{
        backgroundImage: `linear-gradient(rgba(8, 10, 14, 0.82), rgba(8, 10, 14, 0.82)), url("${UI_CHROME.appBackground}")`,
        backgroundPosition: 'center',
        backgroundRepeat: 'repeat',
      }}
    >
      <GameShellCanvasStage
        gameState={gameState}
        visibleGameState={visibleGameState}
        hideSelectionHero={hideSelectionHero}
        canvasCompanionRenderStates={canvasCompanionRenderStates}
        dialogueIndicator={dialogueIndicator}
        sceneTransitionPhase={sceneTransitionPhase}
        sceneTransitionToken={sceneTransitionToken}
        setSelectedSceneEntity={setSelectedSceneEntity}
        setIsMapOpen={setIsMapOpen}
        setSceneTransitionDurations={setSceneTransitionDurations}
      />

      <GameShellMainContent
        gameState={gameState}
        visibleGameState={visibleGameState}
        visibleCurrentStory={visibleCurrentStory}
        isLoading={isLoading}
        aiError={aiError}
        bottomTab={bottomTab}
        setBottomTab={setBottomTab}
        selectionStage={selectionStage}
        setSelectionStage={setSelectionStage}
        isCharacterSelectionStage={isCharacterSelectionStage}
        hasSavedGame={hasSavedGame}
        handleContinueGame={handleContinueGame}
        handleStartNewGame={handleStartNewGame}
        handleWorldSelect={handleWorldSelect}
        handleBackToWorldSelect={handleBackToWorldSelect}
        handleCharacterSelect={handleCharacterSelect}
        displayedOptions={displayedOptions}
        hideStoryOptions={shouldHideStoryOptions}
        canRefreshOptions={canRefreshOptions}
        handleRefreshOptions={handleRefreshOptions}
        handleSceneTransitionChoice={handleSceneTransitionChoice}
        characterChatUi={characterChatUi}
        inventoryUi={inventoryUi}
        battleRewardUi={battleRewardUi}
        questUi={questUi}
        companionRenderStates={companionRenderStates}
        characterChatSummaries={characterChatSummaries}
        openOverlayPanel={openOverlayPanel}
        openCampModal={openCampModal}
        openPartyMemberDetails={openPartyMemberDetails}
        adventureStatistics={adventureStatistics}
        musicVolume={musicVolume}
        onMusicVolumeChange={onMusicVolumeChange}
        resetForSaveAndExit={resetForSaveAndExit}
        handleSaveAndExit={handleSaveAndExit}
      />

      <GameShellOverlays
        gameState={gameState}
        isLoading={isLoading}
        isMapOpen={isMapOpen}
        setIsMapOpen={setIsMapOpen}
        npcUi={npcUi}
        characterChatUi={characterChatUi}
        inventoryUi={inventoryUi}
        companionRenderStates={companionRenderStates}
        characterChatSummaries={characterChatSummaries}
        overlayPanel={overlayPanel}
        closeOverlayPanel={closeOverlayPanel}
        openCampModal={openCampModal}
        openPartyMemberDetails={openPartyMemberDetails}
        shouldMountAdventureEntityModal={shouldMountAdventureEntityModal}
        selectedSceneEntity={selectedSceneEntity}
        closeAdventureEntityModal={closeAdventureEntityModal}
        shouldMountCampModal={shouldMountCampModal}
        showTeamModal={showTeamModal}
        closeCampModal={closeCampModal}
        onBenchCompanion={onBenchCompanion}
        onActivateRosterCompanion={onActivateRosterCompanion}
        shouldMountMapModal={shouldMountMapModal}
        handleMapTravelToScene={handleMapTravelToScene}
        shouldMountCharacterChatModal={shouldMountCharacterChatModal}
        shouldMountNpcModals={shouldMountNpcModals}
      />
    </div>
  );
}

