import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Linking } from "react-native";
import {
  NavigationContainer,
  type LinkingOptions,
  useNavigationContainerRef,
} from "@react-navigation/native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { StatusBar } from "expo-status-bar";
import * as Notifications from "expo-notifications";
import AppNavigator from "./navigation/AppNavigator";
import type { RootStackParamList } from "./navigation/types";
import { SessionProvider, useSession } from "./state/session-context";
import { getNavigationTheme, useTheme } from "./theme";
import { parseNotificationTarget, type NotificationTarget } from "./notifications";

function extractGameId(url: string): string | null {
  try {
    const parsed = new URL(url);
    const path = parsed.pathname || "";
    if (parsed.protocol === "https:" || parsed.protocol === "http:") {
      const match = path.match(/^\/play\/?([^/]+)?/);
      const id = match?.[1]?.trim();
      return id ? id : null;
    }
    if (parsed.host === "play") {
      const id = path.replace(/^\//, "").trim();
      return id ? id : null;
    }
    const fallbackMatch = path.match(/^\/play\/?([^/]+)?/);
    const fallbackId = fallbackMatch?.[1]?.trim();
    return fallbackId ? fallbackId : null;
  } catch {
    return null;
  }
}

function logDeepLink(url: string) {
  if (!__DEV__) return;
  const gameId = extractGameId(url);
  console.log(`[deep-link] url=${url} gameId=${gameId ?? "invalid"}`);
}

function RootNavigationGate() {
  const manager = useSession();
  const navigationRef = useNavigationContainerRef<RootStackParamList>();
  const [navReady, setNavReady] = useState(false);
  const lastTargetRef = useRef<keyof RootStackParamList | null>(null);
  const lastLinkRef = useRef<string | null>(null);
  const pendingNotificationRef = useRef<NotificationTarget | null>(null);
  const lastNotificationIdRef = useRef<string | null>(null);
  const theme = useTheme();
  const navigationTheme = getNavigationTheme(theme);
  const linking = useMemo<LinkingOptions<RootStackParamList>>(
    () => ({
      prefixes: ["negopoly://", "https://negopoly.fr"],
      config: {
        screens: {
          Entry: "play/:gameId",
        },
      },
      getInitialURL: async () => {
        const url = await Linking.getInitialURL();
        if (url) {
          lastLinkRef.current = url;
          logDeepLink(url);
        }
        return url;
      },
      subscribe: (listener) => {
        const onReceiveURL = ({ url }: { url: string }) => {
          if (!url) return;
          if (lastLinkRef.current === url) return;
          lastLinkRef.current = url;
          logDeepLink(url);
          listener(url);
        };
        const subscription = Linking.addEventListener("url", onReceiveURL);
        return () => subscription.remove();
      },
    }),
    [],
  );

  const processPendingNotification = useCallback(() => {
    const pending = pendingNotificationRef.current;
    if (!pending) return;
    if (!navReady || !navigationRef.isReady()) return;
    if (manager.sessionId !== pending.sessionId) return;
    if (!manager.session || manager.session.status !== "active") return;
    pendingNotificationRef.current = null;

    if (pending.type === "chat") {
      const targetStack = manager.isBanker ? "BankerTabs" : "PlayerTabs";
      const targetTab = manager.isBanker ? "BankerChat" : "PlayerChat";
      navigationRef.navigate(
        targetStack as never,
        {
          screen: targetTab,
          params: {
            screen: "ChatThread",
            params: { chatId: pending.chatId },
          },
        } as never,
      );
      return;
    }

    const targetStack = manager.isBanker ? "BankerTabs" : "PlayerTabs";
    const targetTab = manager.isBanker ? "BankerDashboard" : "PlayerHome";
    navigationRef.navigate(
      targetStack as never,
      { screen: targetTab } as never,
    );
  }, [manager.isBanker, manager.session, manager.sessionId, navReady, navigationRef]);

  const handleNotificationResponse = useCallback(
    (response: Notifications.NotificationResponse | null) => {
      if (!response) return;
      const identifier = response.notification.request.identifier;
      if (identifier && lastNotificationIdRef.current === identifier) return;
      if (identifier) {
        lastNotificationIdRef.current = identifier;
      }
      const target = parseNotificationTarget(
        response.notification.request.content.data,
      );
      if (!target) return;
      if (__DEV__) {
        console.log(
          `[push] target=${target.type} session=${target.sessionId}` +
            (target.type === "chat" ? ` chat=${target.chatId}` : ""),
        );
      }
      pendingNotificationRef.current = target;
      processPendingNotification();
    },
    [processPendingNotification],
  );

  useEffect(() => {
    if (!navReady || !navigationRef.isReady()) return;

    let target: keyof RootStackParamList;
    if (!manager.sessionId) {
      target = "Entry";
    } else if (!manager.session) {
      target = manager.connectionState === "error" ? "Entry" : "Lobby";
    } else if (manager.session.status === "lobby") {
      target = "Lobby";
    } else if (manager.isBanker) {
      target = "BankerTabs";
    } else {
      target = "PlayerTabs";
    }

    const currentRoute = navigationRef.getCurrentRoute();
    if (currentRoute?.name === target || lastTargetRef.current === target) {
      return;
    }

    navigationRef.reset({
      index: 0,
      routes: [{ name: target }],
    });
    lastTargetRef.current = target;
  }, [
    manager.sessionId,
    manager.session,
    manager.isBanker,
    manager.connectionState,
    navReady,
    navigationRef,
  ]);

  useEffect(() => {
    processPendingNotification();
  }, [processPendingNotification]);

  useEffect(() => {
    let mounted = true;
    Notifications.getLastNotificationResponseAsync().then((response) => {
      if (!mounted) return;
      handleNotificationResponse(response);
    });
    const subscription = Notifications.addNotificationResponseReceivedListener(
      (response) => {
        handleNotificationResponse(response);
      },
    );
    return () => {
      mounted = false;
      subscription.remove();
    };
  }, [handleNotificationResponse]);

  return (
    <NavigationContainer
      ref={navigationRef}
      onReady={() => setNavReady(true)}
      linking={linking}
      theme={navigationTheme}
    >
      <AppNavigator />
    </NavigationContainer>
  );
}

export default function App() {
  const theme = useTheme();
  return (
    <SafeAreaProvider>
      <StatusBar
        style={theme.dark ? "light" : "dark"}
        backgroundColor={theme.colors.background}
      />
      <SessionProvider>
        <RootNavigationGate />
      </SessionProvider>
    </SafeAreaProvider>
  );
}
