import { STORAGE_KEYS } from '@/common/constants/storageKeys';
import { connectSync, disconnectAndClear } from '@/remote/database';
import * as SecureStore from 'expo-secure-store';
import { ReactNode, createContext, useContext, useEffect, useState } from 'react';
import { sendMagicCode, verifyMagicCode } from './api';

interface User {
  id: string;
  email: string;
}

interface AuthContextType {
  user: User | null;
  isLoading: boolean;
  signInWithEmail: (email: string) => Promise<{ success: boolean; message?: string }>;
  verifyOtp: (email: string, code: string) => Promise<{ success: boolean; message?: string }>;
  signOut: () => Promise<void>;
}

const AuthContext = createContext<AuthContextType | null>(null);

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);

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

  useEffect(() => {
    if (user) {
      connectSync().catch(console.error);
    }
  }, [user?.id]);

  async function restoreSession() {
    try {
      const [token, userData] = await Promise.all([
        SecureStore.getItemAsync(STORAGE_KEYS.SESSION_TOKEN),
        SecureStore.getItemAsync(STORAGE_KEYS.USER_DATA),
      ]);

      if (token && userData) {
        setUser(JSON.parse(userData) as User);
      }
    } catch (e) {
      console.error('Error restoring session:', e);
    } finally {
      setIsLoading(false);
    }
  }

  const signInWithEmail = async (email: string) => {
    return await sendMagicCode(email);
  };

  const verifyOtp = async (email: string, code: string) => {
    const result = await verifyMagicCode(email, code);

    if (result.success && result.sessionToken && result.userId) {
      const newUser = { id: result.userId, email };
      setUser(newUser);

      await SecureStore.setItemAsync(STORAGE_KEYS.SESSION_TOKEN, result.sessionToken);
      await SecureStore.setItemAsync(STORAGE_KEYS.USER_DATA, JSON.stringify(newUser));
    }

    return result;
  };

  const signOut = async () => {
    setUser(null);
    await disconnectAndClear();
    await SecureStore.deleteItemAsync(STORAGE_KEYS.SESSION_TOKEN);
    await SecureStore.deleteItemAsync(STORAGE_KEYS.USER_DATA);
  };

  return (
    <AuthContext.Provider
      value={{
        user,
        isLoading,
        signInWithEmail,
        verifyOtp,
        signOut,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
}
