import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import 'react-native-reanimated';
import { useColorScheme } from '@/hooks/useColorScheme';
import React, { useState, useEffect, useRef } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import UserSelection from '@/components/UserSelection';
import { TouchableOpacity, Text, View } from 'react-native';
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import Constants from 'expo-constants';

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

type User = {
  id: number;
  name: string;
  message: string;
};

export default function RootLayout() {
  const API_KEY = process.env.EXPO_PUBLIC_API_KEY;
  const BASE_URL = process.env.EXPO_PUBLIC_BASE_URL;

  const colorScheme = useColorScheme();
  const [loaded, error] = useFonts({
    SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
  });
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  
  // Push Notifications state
  const [expoPushToken, setExpoPushToken] = useState<string | null>(null);
  const notificationListener = useRef<Notifications.Subscription>();
  const responseListener = useRef<Notifications.Subscription>();

  useEffect(() => {
    async function prepare() {
      try {
        // Load the user
        const storedUser = await AsyncStorage.getItem('@user');
        if (storedUser) {
          setUser(JSON.parse(storedUser));
        }
      } catch (e) {
        console.error('Failed to load user', e);
      } finally {
        setIsLoading(false);
      }
    }

    prepare();
  }, []);

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  const handleUserSelected = async (selectedUser: User) => {
    console.log('User selected:', selectedUser); // Debug log
    try {
      await AsyncStorage.setItem('@user', JSON.stringify(selectedUser));
      console.log('User data stored in AsyncStorage:', selectedUser); // Debug log
      setUser(selectedUser);
    } catch (e) {
      console.error('Failed to save user or push token', e);
    }
  };

  const handleSwitchUser = async () => {
    try {
      await AsyncStorage.removeItem('@user');
      setUser(null);
    } catch (e) {
      console.error('Failed to remove user', e);
    }
  };

  /** --- PUSH NOTIFICATIONS LOGIC --- **/

useEffect(() => {
  // Register for push notifications and set the push token
  registerForPushNotificationsAsync().then(async (token) => {
    const storedUser = await AsyncStorage.getItem('@user');
    if (!storedUser) {
      console.log('No user found in AsyncStorage'); // Debug log
      return;
    }
    try {
      const storedUser = await AsyncStorage.getItem('@user');
      console.log('Stored user data:', storedUser); // Debug log

      if (storedUser) {
        const user = JSON.parse(storedUser);
        console.log('Parsed user data:', user); // Debug log

        // Send the push token to your Next.js API
        await fetch(`${BASE_URL}/updatePushToken`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            apiKey: API_KEY,
            userId: user.id,
            pushToken: token,
          }),
        });
        console.log('Push token update request sent with user ID:', user.id); // Debug log
      } else {
        console.log('No user found in AsyncStorage');
      }
    } catch (error) {
      console.error('Failed to send push token to backend', error);
    }
  });

  // Listener for received notifications while the app is running
  notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
    console.log('Notification Received: ', notification);
  });

  // Listener for when the user interacts with a notification
  responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
    console.log('User interacted with notification: ', response);
  });

  // Clean up listeners when component unmounts
  return () => {
    if (notificationListener.current) {
      Notifications.removeNotificationSubscription(notificationListener.current);
    }
    if (responseListener.current) {
      Notifications.removeNotificationSubscription(responseListener.current);
    }
  };
}, []);

  if (!loaded || isLoading) {
    return null; // or a more elegant loading indicator
  }

  if (!user) {
    return <UserSelection onUserSelected={handleUserSelected} />;
  }

  return (
    <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
      <Stack>
        <Stack.Screen 
          name="(tabs)" 
          options={{ 
            headerShown: true,
            title: user.name,
            headerRight: () => (
              <TouchableOpacity onPress={handleSwitchUser} style={{ marginRight: 15 }}>
                <Text style={{ color: colorScheme === 'dark' ? 'white' : 'black' }}>
                  Switch User
                </Text>
              </TouchableOpacity>
            ),
          }} 
        />
        <Stack.Screen name="+not-found" />
      </Stack>

      {/* You can display the push token for debug purposes */}
      {expoPushToken && (
        <View style={{ padding: 10 }}>
          <Text>Your Push Token: {expoPushToken}</Text>
        </View>
      )}
    </ThemeProvider>
  );
}

/** --- Helper functions for push notifications --- **/

// Function to get the push token and request permissions
async function registerForPushNotificationsAsync() {
  let token;

  // Ensure you're running on a physical device
  if (Device.isDevice) {
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;

    // Ask user for permission if not granted already
    if (existingStatus !== 'granted') {
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }

    if (finalStatus !== 'granted') {
      console.log('Failed to get push notification token because permission not granted.');
      return null;
    }

    try {
      token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log('Expo Push Token:', token);
    } catch (error) {
      console.log('Failed to get Expo push token:', error);
      return null;
    }
  } else {
    console.log('Must use physical device for push notifications');
  }

  return token;
}
