import { setApiAccessToken } from '@/lib/api-client';
import { createAuthClient } from 'better-auth/react';
import { emailOTPClient } from 'better-auth/client/plugins';
import type { User, Session } from 'better-auth/types';
import type { PropsWithChildren } from 'react';
import { createContext, useContext, useEffect, useMemo, useState } from 'react';

const authClient = createAuthClient({
  baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000',
  plugins: [emailOTPClient()],
});

type SignInParams = {
  email: string;
  password: string;
};

type SignUpParams = {
  email: string;
  password: string;
  name: string;
};

type UpdateProfileParams = {
  fullName: string;
};

type UpdatePasswordParams = {
  password: string;
};

type AuthUser = User | null;
type AuthSession = Session | null;

export type AuthContextValue = {
  user: AuthUser;
  session: AuthSession;
  loading: boolean;
  isAuthenticated: boolean;
  displayName: string;
  initials: string;
  avatarUrl: string | null;
  signInWithPassword: (params: SignInParams) => Promise<void>;
  signUp: (params: SignUpParams) => Promise<void>;
  updateProfile: (params: UpdateProfileParams) => Promise<void>;
  updatePassword: (params: UpdatePasswordParams) => Promise<void>;
  signOut: () => Promise<void>;
};

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

function getDisplayName(user: AuthUser): string {
  if (!user) return 'Usuario';

  const name = user.name ?? user.email ?? 'Usuario';
  return name;
}

function getInitials(name: string): string {
  const words = name.trim().split(/\s+/).slice(0, 2);
  const initials = words.map((word) => word[0]?.toUpperCase() ?? '').join('');
  return initials || 'U';
}

function getAvatarUrl(user: AuthUser): string | null {
  if (!user) return null;
  return user.image ?? null;
}

export function AuthProvider({ children }: PropsWithChildren) {
  const sessionStore = authClient.useSession();
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(sessionStore.isPending);
  }, [sessionStore.isPending]);

  const user = sessionStore.data?.user ?? null;
  const session = sessionStore.data?.session ?? null;
  const isAuthenticated = !!session;

  useEffect(() => {
    if (sessionStore.data?.session?.token) {
      setApiAccessToken(sessionStore.data.session.token);
    } else {
      setApiAccessToken(null);
    }
  }, [sessionStore.data?.session?.token]);

  const value = useMemo<AuthContextValue>(() => {
    const displayName = getDisplayName(user);
    const initials = getInitials(displayName);
    const avatarUrl = getAvatarUrl(user);

    return {
      user,
      session,
      loading,
      isAuthenticated,
      displayName,
      initials,
      avatarUrl,
      signInWithPassword: async ({ email, password }) => {
        const result = await authClient.signIn.email({
          email,
          password,
        });

        if (result.error) {
          throw new Error(result.error.message);
        }
      },
      signUp: async ({ email, password, name }) => {
        const result = await authClient.signUp.email({
          email,
          password,
          name,
        });

        if (result.error) {
          throw new Error(result.error.message);
        }
      },
      updateProfile: async ({ fullName }) => {
        const result = await (authClient as any).user.update({
          name: fullName,
        });

        if (result?.error) {
          throw new Error(result.error.message);
        }
      },
      updatePassword: async ({ password }) => {
        const result = await (authClient as any).user.update({
          password,
        });

        if (result?.error) {
          throw new Error(result.error.message);
        }
      },
      signOut: async () => {
        const result = await authClient.signOut();

        if (result.error) {
          throw new Error(result.error.message);
        }
      },
    };
  }, [loading, session, user, isAuthenticated, sessionStore]);

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export function useAuth() {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error('useAuth must be used within AuthProvider');
  }

  return context;
}

export { authClient };
