"use client";
import { useEffect } from "react";
import { MotionConfig } from "framer-motion";
import { HomeScreen } from "@/components/HomeScreen";
import { GameScreen } from "@/components/screens/GameScreen";
import { ProfileScreen } from "@/components/screens/ProfileScreen";
import { FriendsScreen } from "@/components/screens/FriendsScreen";
import { OnlineLobbyScreen } from "@/components/screens/OnlineLobbyScreen";
import { RoomScreen } from "@/components/screens/RoomScreen";
import { MatchmakingScreen } from "@/components/screens/MatchmakingScreen";
import { LeaderboardScreen } from "@/components/screens/LeaderboardScreen";
import { ShopScreen } from "@/components/screens/ShopScreen";
import { BuyCoinsScreen } from "@/components/screens/BuyCoinsScreen";
import { AchievementsScreen } from "@/components/screens/AchievementsScreen";
import { ChatScreen } from "@/components/screens/ChatScreen";
import { NotificationsScreen } from "@/components/screens/NotificationsScreen";
import { AuthScreen } from "@/components/screens/AuthScreen";
import { DailyRewardModal } from "@/components/online/DailyRewardModal";
import { NotificationToaster } from "@/components/online/NotificationToaster";
import { ResumeGameBar } from "@/components/online/ResumeGameBar";
import { CelebrationOverlay } from "@/components/online/CelebrationOverlay";
import { PublicProfileModal } from "@/components/online/PublicProfileModal";
import { CapacitorBack } from "@/components/CapacitorBack";
import { useSessionStore } from "@/lib/session-store";
import { useGameStore } from "@/lib/game-store";
import { useOnlineStore } from "@/lib/online-store";
import { useNotifStore, pushNotification } from "@/lib/notification-store";
import { getService } from "@/lib/online/service";
import { captureBazaarRedirect } from "@/lib/storeBilling";
import { screenFromHash, useUIStore, type Screen } from "@/lib/ui-store";
/** Transient screens can't be restored without their state — fall back to home. */
function resolveScreen(s: Screen): Screen {
switch (s) {
case "game":
return useGameStore.getState().started ? s : "home";
case "room":
return useOnlineStore.getState().room ? s : "home";
case "chat":
return useOnlineStore.getState().activeChatFriend ? s : "home";
case "matchmaking":
return useOnlineStore.getState().matchmaking.phase !== "idle" ? s : "home";
default:
return s;
}
}
export default function Page() {
const screen = useUIStore((s) => s.screen);
const init = useSessionStore((s) => s.init);
const loading = useSessionStore((s) => s.loading);
useEffect(() => {
init();
// ZarinPal payment return (?pay=success&coins= / ?pay=failed)
const params = new URLSearchParams(window.location.search);
const pay = params.get("pay");
if (pay) {
if (pay === "success") {
const coins = params.get("coins");
pushNotification({
kind: "system",
titleFa: "پرداخت موفق",
titleEn: "Payment successful",
bodyFa: coins ? `${coins} سکه به حساب شما اضافه شد` : undefined,
bodyEn: coins ? `${coins} coins added` : undefined,
icon: "💰",
});
useSessionStore.getState().refreshProfile();
} else {
pushNotification({ kind: "system", titleFa: "پرداخت ناموفق بود", titleEn: "Payment failed", icon: "⚠️" });
}
window.history.replaceState({}, "", window.location.pathname);
}
// Cafe Bazaar in-app purchase return (?purchaseToken=...) → verify + credit.
const iab = captureBazaarRedirect();
if (iab && iab.productId) {
getService()
.verifyIab(iab.store, iab.productId, iab.token)
.then((v) => {
if (v.ok) {
if (v.profile) useSessionStore.setState({ profile: v.profile });
pushNotification({
kind: "system",
titleFa: "پرداخت موفق",
titleEn: "Payment successful",
bodyFa: v.coins ? `${v.coins.toLocaleString()} سکه اضافه شد` : undefined,
bodyEn: v.coins ? `${v.coins.toLocaleString()} coins added` : undefined,
icon: "💰",
});
} else {
pushNotification({ kind: "system", titleFa: "پرداخت ناموفق بود", titleEn: "Payment failed", icon: "⚠️" });
}
})
.finally(() => window.history.replaceState({}, "", window.location.pathname));
}
useUIStore.getState().initHistory();
useNotifStore.getState().init();
// surface a daily-reward notification if it's available
getService()
.getDailyState()
.then((d) => {
if (d.available)
pushNotification({
kind: "daily",
titleFa: "پاداش روزانه آماده است",
titleEn: "Daily reward is ready",
icon: "🎁",
});
})
.catch(() => {});
// Resume an in-progress server match after a full reload: the server
// re-broadcasts state on (re)connect — if we're not already in a game and
// not mid-matchmaking, re-enter live mode (minimized) so the resume pill shows.
const svc = getService();
let resumeUnsub: (() => void) | undefined;
let rewardUnsub: (() => void) | undefined;
if (svc.live) {
resumeUnsub = svc.onState((s) => {
const gs = useGameStore.getState();
const scr = useUIStore.getState().screen;
if (
!gs.started &&
scr !== "matchmaking" &&
scr !== "game" &&
s.matchWinner == null &&
s.phase !== "match-over"
) {
gs.enterServerMatch(svc);
gs.applyServerState(s);
gs.minimize();
}
});
// Nudge the player when a match they left finishes while they're away.
rewardUnsub = svc.onReward(() => {
if (useUIStore.getState().screen !== "game")
pushNotification({
kind: "system",
titleFa: "بازی به پایان رسید",
titleEn: "Match ended",
bodyFa: "نتیجه و جایزه را ببینید",
bodyEn: "See the result and reward",
icon: "🏆",
});
});
}
const onPop = (e: PopStateEvent) => {
const raw = ((e.state?.screen as Screen) ?? screenFromHash());
useUIStore.getState().syncFromPop(resolveScreen(raw));
};
window.addEventListener("popstate", onPop);
return () => {
window.removeEventListener("popstate", onPop);
resumeUnsub?.();
rewardUnsub?.();
};
}, [init]);
return (
// reducedMotion="user" makes every Framer Motion animation honor the OS
// "reduce motion" accessibility setting (coin rain, confetti, count-ups…).
{renderScreen(screen)}
{loading && null}
);
}
function renderScreen(screen: string) {
switch (screen) {
case "game":
return ;
case "auth":
return ;
case "profile":
return ;
case "friends":
return ;
case "online":
return ;
case "room":
return ;
case "matchmaking":
return ;
case "leaderboard":
return ;
case "shop":
return ;
case "buycoins":
return ;
case "achievements":
return ;
case "chat":
return ;
case "notifications":
return ;
default:
return ;
}
}