import { ConstEnv } from '@/constants/ConstEnv';
import { apiRegisteredToken, apiUnregisteredToken } from '@/lib/api';
import { getToken } from '@/lib/useNotification';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useQueryClient } from '@tanstack/react-query';
import CryptoES from "crypto-es";
import { router } from "expo-router";
import { createContext, MutableRefObject, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react';

const AuthContext = createContext<{
  signIn: (arg0: string) => void;
  signOut: () => void
  decryptToken: (arg0: string) => Promise<string>
  encryptToken: (arg0: string) => Promise<string>
  token: MutableRefObject<string | null> | null;
  isLoading: boolean
}>({
  signIn: () => null,
  signOut: () => null,
  decryptToken: () => Promise.resolve(''),
  encryptToken: () => Promise.resolve(''),
  token: null,
  isLoading: true
});

// This hook can be used to access the user info.
export function useAuthSession() {
  return useContext(AuthContext);
}

export default function AuthProvider({ children }: { children: ReactNode }): ReactNode {
  const tokenRef = useRef<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const queryClient = useQueryClient();

  useEffect(() => {
    (async (): Promise<void> => {
      const token = await AsyncStorage.getItem('@token');
      tokenRef.current = token || '';
      setIsLoading(false);
    })()
  }, []);

  const decryptToken = (async (token: string) => {
    var Decrypted = CryptoES.AES.decrypt(token, ConstEnv.pass_encrypt);
    var result = Decrypted.toString(CryptoES.enc.Utf8);
    return result
  })

  const encryptToken = (async (token: string) => {
    var result = CryptoES.AES.encrypt(token, ConstEnv.pass_encrypt).toString();
    return result
  })

  const signIn = useCallback(async (token: string) => {
    const hasil = await decryptToken(String(token))
    const permissionStorage = await AsyncStorage.getItem('@notification_permission')
    if (permissionStorage === "true") {
      const tokenDevice = await getToken()
      try {
        await apiRegisteredToken({ user: hasil, token: String(tokenDevice) })
      } catch (error) {
        console.error(error)
      } finally {
        await AsyncStorage.setItem('@token', token);
        tokenRef.current = token;
        router.replace('/home')
        return true
      }
    } else {
      await apiRegisteredToken({ user: hasil, token: "" })
      await AsyncStorage.setItem('@token', token);
      tokenRef.current = token;
      router.replace('/home')
    }
  }, []);

  const signOut = useCallback(async () => {
    try {
      const hasil = await decryptToken(String(tokenRef.current))
      // if (Platform.OS === 'android') {
      const token = await getToken()
      await apiUnregisteredToken({ user: hasil, token: String(token) })
      // }else{
      //   const response = await apiUnregisteredToken({ user: hasil, token: "" })
      // }
    } catch (error) {
      console.error(error)
    } finally {
      await AsyncStorage.setItem('@token', '');
      tokenRef.current = null;
      queryClient.clear();
      router.replace('/');
    }
  }, []);

  return (
    <AuthContext.Provider
      value={{
        signIn,
        signOut,
        token: tokenRef,
        decryptToken,
        encryptToken,
        isLoading
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};