import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Linking, StyleSheet, View } from "react-native";
import {
  CommonActions,
  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 { normalizeScreenshotScene } from "./dev/screenshot-fixtures";
import type { RootStackParamList } from "./navigation/types";
import { SessionProvider, useSession } from "./state/session-context";
import { getNavigationTheme, useTheme } from "./theme";
import { parseNotificationTarget, type NotificationTarget } from "./notifications";
import ConnectionBanner from "./components/ConnectionBanner";

function getUrlSegments(url: string): string[] {
  try {
    const parsed = new URL(url);
    const pathSegments = (parsed.pathname || "")
      .split("/")
      .map((segment) => segment.trim())
      .filter(Boolean);
    if (parsed.protocol === "https:" || parsed.protocol === "http:") {
      return pathSegments;
    }
    if (parsed.host) {
      return [parsed.host, ...pathSegments];
    }
    return pathSegments;
  } catch {
    return [];
  }
}

function extractGameId(url: string): string | null {
  const segments = getUrlSegments(url);
  if (segments[0] !== "play") return null;
  return segments[1] || null;
}

function extractScreenshotScene(url: string) {
  const segments = getUrlSegments(url);
  if (segments[0] !== "screenshot") return null;
  return normalizeScreenshotScene(segments[1]);
}

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

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 pendingScreenshotRef = useRef(false);
  const lastNotificationIdRef = useRef<string | null>(null);
  const theme = useTheme();
  const navigationTheme = getNavigationTheme(theme);
  const handleSpecialUrl = useCallback(
    (url: string) => {
      const scene = extractScreenshotScene(url);
      if (!scene) return false;
      pendingScreenshotRef.current = true;
      manager.activateScreenshotScene(scene);
      return true;
    },
    [manager.activateScreenshotScene],
  );
  const linking = useMemo<LinkingOptions<RootStackParamList>>(
    () => ({
      prefixes: ["negopoly://", "https://negopoly.fr"],
      config: {
        screens: {
          AgencyJoin: "play/:gameId",
        },
      },
      getInitialURL: async () => {
        const url = await Linking.getInitialURL();
        if (url) {
          lastLinkRef.current = url;
          logDeepLink(url);
          if (handleSpecialUrl(url)) {
            return null;
          }
        }
        return url;
      },
      subscribe: (listener) => {
        const onReceiveURL = ({ url }: { url: string }) => {
          if (!url) return;
          if (lastLinkRef.current === url) return;
          lastLinkRef.current = url;
          logDeepLink(url);
          if (handleSpecialUrl(url)) return;
          listener(url);
        };
        const subscription = Linking.addEventListener("url", onReceiveURL);
        return () => subscription.remove();
      },
    }),
    [handleSpecialUrl],
  );

  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.dispatch(
        CommonActions.navigate({
          name: targetStack,
          params: {
            screen: targetTab,
            params: {
              screen: "ChatThread",
              params: { chatId: pending.chatId },
            },
          },
        }),
      );
      return;
    }

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

  const processPendingScreenshot = useCallback(() => {
    if (!pendingScreenshotRef.current) return;
    if (!navReady || !navigationRef.isReady()) return;
    const target = manager.screenshot?.navigationTarget;
    if (!target) return;

    pendingScreenshotRef.current = false;
    navigationRef.dispatch(
      CommonActions.reset({
        index: 0,
        routes: [
          {
            name: target.root,
            params: target.params,
          },
        ],
      }),
    );
    lastTargetRef.current = target.root;
  }, [manager.screenshot, 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 (pendingScreenshotRef.current) {
      return;
    }
    if (!navReady || !navigationRef.isReady()) return;

    const currentRoute = navigationRef.getCurrentRoute();
    const currentName = currentRoute?.name;
    const inEntryFlow =
      currentName === "EntryLanding" ||
      currentName === "AgencyJoin" ||
      currentName === "AgencyCreate";

    let target: keyof RootStackParamList;
    if (!manager.sessionId) {
      if (inEntryFlow) {
        lastTargetRef.current = currentName ?? null;
        return;
      }
      target = "EntryLanding";
    } else if (!manager.session) {
      target = "Lobby";
    } else if (manager.session.status === "lobby") {
      target = "Lobby";
    } else if (manager.isBanker) {
      target = "BankerTabs";
    } else {
      target = "PlayerTabs";
    }

    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(() => {
    processPendingScreenshot();
  }, [processPendingScreenshot]);

  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 (
    <View style={styles.container}>
      <NavigationContainer
        ref={navigationRef}
        onReady={() => setNavReady(true)}
        linking={linking}
        theme={navigationTheme}
      >
        <AppNavigator />
        <ConnectionBanner
          visible={
            Boolean(manager.sessionId) &&
            manager.connectionState !== "idle" &&
            manager.connectionState !== "open"
          }
          connectionState={manager.connectionState}
          reconnectAttempt={manager.reconnectAttempt}
          onRetry={manager.retryConnection}
        />
      </NavigationContainer>
    </View>
  );
}

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

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});
