'use client';
import { useEffect, useState, lazy, Suspense } from 'react';
import { useGameStore, useGameLoop, fmt, getFloorElement, computeMaxMana, computeRegen, computeClickMana, getMeditationBonus, getIncursionStrength, canAffordSpellCost } from '@/lib/game/store';
import { ActivityLogEntry } from '@/lib/game/types';
import { getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/computed-stats';
import { ELEMENTS, GUARDIANS, SPELLS_DEF, PRESTIGE_DEF, getStudySpeedMultiplier, getStudyCostMultiplier } from '@/lib/game/constants';
import { getUnifiedEffects, hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from '@/components/ui/scroll-area';
import { RotateCcw, Mountain, ChevronDown } from 'lucide-react';
import { TooltipProvider } from '@/components/ui/tooltip';
import { DebugName } from '@/lib/game/debug-context';
// Non-tab component imports
import { ActionButtons, CalendarDisplay, ManaDisplay, TimeDisplay } from '@/components/game';
// Loot and Achievements moved to separate tabs
// Lazy load tab components
const SpireTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.SpireTab })));
const SkillsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.SkillsTab })));
const SpellsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.SpellsTab })));
const LabTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.LabTab })));
const StatsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.StatsTab })));
const EquipmentTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.EquipmentTab })));
const AttunementsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.AttunementsTab })));
const DebugTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.DebugTab })));
const LootTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.LootTab })));
const AchievementsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.AchievementsTab })));
const GolemancyTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.GolemancyTab })));
const CraftingTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.CraftingTab })));
// Loading fallback component
const TabLoadingFallback = () =>
Loading...
;
export default function ManaLoopGame() {
const [activeTab, setActiveTab] = useState('spire');
const [isGathering, setIsGathering] = useState(false);
// Game store
const store = useGameStore();
const gameLoop = useGameLoop();
// Computed effects from upgrades and equipment
const upgradeEffects = getUnifiedEffects(store);
// Derived stats
const maxMana = computeMaxMana(store, upgradeEffects);
const baseRegen = computeRegen(store, upgradeEffects);
const clickMana = computeClickMana(store);
const floorElem = getFloorElement(store.currentFloor);
const floorElemDef = ELEMENTS[floorElem];
const isGuardianFloor = !!GUARDIANS[store.currentFloor];
const currentGuardian = GUARDIANS[store.currentFloor];
const meditationMultiplier = getMeditationBonus(store.meditateTicks, store.skills, upgradeEffects.meditationEfficiency);
const incursionStrength = getIncursionStrength(store.day, store.hour);
const studySpeedMult = getStudySpeedMultiplier(store.skills);
const studyCostMult = getStudyCostMultiplier(store.skills);
// Effective regen with incursion penalty
const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength);
// Mana Cascade bonus
const manaCascadeBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_CASCADE)
? Math.floor(maxMana / 100) * 0.1
: 0;
// Effective regen
const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus) * meditationMultiplier;
// Get all active spells from equipment
const activeEquipmentSpells = getActiveEquipmentSpells(store.equippedInstances, store.equipmentInstances);
// Compute total DPS
const totalDPS = getTotalDPS(store, upgradeEffects, floorElem);
// Auto-gather while holding
useEffect(() => {
if (!isGathering) return;
let lastGatherTime = 0;
const minGatherInterval = 100;
let animationFrameId: number;
const gatherLoop = (timestamp: number) => {
if (timestamp - lastGatherTime >= minGatherInterval) {
store.gatherMana();
lastGatherTime = timestamp;
}
animationFrameId = requestAnimationFrame(gatherLoop);
};
animationFrameId = requestAnimationFrame(gatherLoop);
return () => cancelAnimationFrame(animationFrameId);
}, [isGathering, store]);
// Handle gather button events
const handleGatherStart = () => {
setIsGathering(true);
store.gatherMana();
};
const handleGatherEnd = () => {
setIsGathering(false);
};
// Start game loop
useEffect(() => {
const cleanup = gameLoop.start();
return cleanup;
}, [gameLoop]);
// Check if spell can be cast
const canCastSpell = (spellId: string): boolean => {
const spell = SPELLS_DEF[spellId];
if (!spell) return false;
return canAffordSpellCost(spell.cost, store.rawMana, store.elements);
};
// Game Over Screen
if (store.gameOver) {
return (
{store.victory ? 'VICTORY!' : 'LOOP ENDS'}
{store.victory
? 'The Awakened One falls! Your power echoes through eternity.'
: 'The time loop resets... but you remember.'}
{fmt(store.loopInsight)}
Insight Gained
{store.maxFloorReached}
Best Floor
{store.signedPacts.length}
Pacts Signed
{store.loopCount + 1}
Total Loops
store.startNewLoop()}
>
Begin New Loop
);
}
return (
{/* Header */}
{/* Main Content */}
{/* Left Panel - Mana & Actions */}
{/* Mana Display */}
{/* Climb the Spire Button - only show when not in Spire Mode */}
{!store.spireMode && (
store.enterSpireMode()}
>
Climb the Spire
)}
{/* Action Buttons - only show when not in Spire Mode */}
{!store.spireMode && (
)}
{/* Calendar */}
{/* Loot and Achievements moved to tabs */}
{/* Right Panel - Conditional rendering based on Spire Mode */}
{store.spireMode ? (
/* Spire Mode - Simplified UI */
๐๏ธ Spire Mode - Floor {store.currentFloor}
{/* Show Climbing indicator when actively climbing */}
{store.currentAction === 'climb' && !store.isDescending && (
Climbing
)}
store.climbDownFloor()}
disabled={store.isDescending}
>
{store.isDescending ? 'Descendingโฆ' :
store.currentAction === 'climb' ? 'Climbing' :
'Begin Descent'}
store.exitSpireMode()}
>
Exit Spire
}>
{/* Activity Log for Spire Mode */}
Activity Log
{(store.activityLog || []).slice(0, 50).map((entry: ActivityLogEntry, i) => {
// Style based on event type
const getEventStyle = (eventType: string) => {
switch (eventType) {
case 'enemy_defeated':
case 'floor_cleared':
return 'text-green-400';
case 'damage_dealt':
return 'text-red-400';
case 'dodge':
return 'text-yellow-400';
case 'armor_proc':
return 'text-blue-400';
case 'special_effect':
return 'text-purple-400';
case 'floor_transition':
return 'text-cyan-400';
case 'spell_cast':
return 'text-amber-400';
case 'golem_attack':
return 'text-orange-400';
case 'puzzle_solved':
return 'text-pink-400';
default:
return 'text-gray-300';
}
};
return (
{entry.message}
);
})}
{(store.activityLog || []).length === 0 && (
No activity yet...
)}
) : (
/* Normal Mode - Tabs */
โ๏ธ Spire
โจ Attune
๐ฟ Golems
๐ Skills
๐ฎ Spells
๐ก๏ธ Gear
๐ง Craft
๐ Loot
๐ Achieve
๐ฌ Lab
๐ Stats
๐ง Debug
๐ Grimoire
}>
}>
}>
}>
}>
}>
}>
}>
}>
}>
}>
{renderGrimoireTab()}
}>
)}
);
// Grimoire Tab (Prestige)
function renderGrimoireTab() {
return (
{/* Current Status */}
Loop Status
{store.loopCount}
Loops Completed
{fmt(store.insight)}
Current Insight
{fmt(store.totalInsight)}
Total Insight
{store.memorySlots}
Memory Slots
{/* Signed Pacts */}
Signed Pacts
{store.signedPacts.length === 0 ? (
No pacts signed yet. Defeat guardians to earn pacts.
) : (
{store.signedPacts.map((floor) => {
const guardian = GUARDIANS[floor];
if (!guardian) return null;
return (
{guardian.name}
Floor {floor}
{guardian.pact}x multiplier
);
})}
)}
{/* Prestige Upgrades */}
Insight Upgrades (Permanent)
{Object.entries(PRESTIGE_DEF).map(([id, def]) => {
const level = store.prestigeUpgrades[id] || 0;
const maxed = level >= def.max;
const canBuy = !maxed && store.insight >= def.cost;
return (
{def.name}
{level}/{def.max}
{def.desc}
store.doPrestige(id)}
>
{maxed ? 'Maxed' : `Upgrade (${fmt(def.cost)} insight)`}
);
})}
{/* Reset Game Button */}
Reset All Progress
Clear all data and start fresh
{
if (confirm('Are you sure you want to reset ALL progress? This cannot be undone!')) {
store.resetGame();
}
}}
>
Reset
);
}
}