import {
  ReactNode,
  createContext,
  useContext,
  useEffect,
  useState,
} from 'react';

import { UserCredentials } from '@supabase/gotrue-js';
import { supabase } from 'utils/supabaseClient';

type authContextType = {
  user: boolean;
  login: () => void;
  logout: () => void;
};

type Properties = {
  children: ReactNode;
};

const authContextDefaultValues: authContextType = {
  user: false,
  login: () => {},
  logout: () => {},
};

// create a context for authentication
const AuthContext = createContext<authContextType>(authContextDefaultValues);

export const AuthProvider = ({ children }: Properties): JSX.Element => {
  const [user, setUser] = useState(supabase.auth.session()?.user);
  const [session, setSession] = useState(supabase.auth.session());
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Check active sessions and sets the user
    const session = supabase.auth.session();

    setUser(session?.user);
    setSession(session);
    setLoading(false);

    // Listen for changes on auth state (logged in, signed out, etc.)
    const { data: listener } = supabase.auth.onAuthStateChange(
      (event, session): void => {
        if (event === 'SIGNED_OUT' || event === 'SIGNED_IN') {
          void fetch('/api/auth', {
            method: 'POST',
            headers: new Headers({ 'Content-Type': 'application/json' }),
            credentials: 'same-origin',
            body: JSON.stringify({ event, session }),
          }).then((response) => response.json());
        }
        setUser(session?.user);
        setSession(session);
        setLoading(false);
      }
    );

    return () => {
      listener?.unsubscribe();
    };
  }, []);

  // Will be passed down to Signup, Login and Dashboard components
  const value = {
    signUp: (data: UserCredentials) => supabase.auth.signUp(data),
    signIn: (data: UserCredentials) => supabase.auth.signIn(data),
    signOut: () => supabase.auth.signOut(),
    resetPassword: (data: string) =>
      supabase.auth.api.resetPasswordForEmail(data),
    user,
    session,
  };

  return (
    <AuthContext.Provider value={value}>
      {!loading && children}
    </AuthContext.Provider>
  );
};

// export the useAuth hook
export const useAuth = () => useContext(AuthContext);
