'use client';

import { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { useLanguage } from './LanguageContext';
import type {
  AuthUser,
  AuthSession,
  SignInResult,
  SignUpMetadata,
  SignUpResult,
} from '@client/types/auth';

interface AuthContextType {
  user: Pick<AuthUser, 'id' | 'email'> | null;
  session: AuthSession | null;
  loading: boolean;
  restaurantId: string | null;
  branchId: string | null;
  /**
   * Literal branch on the JWT session — `null` when an owner has chosen
   * the "All branches" view, otherwise the same as `branchId`. Use this
   * (not `branchId`) when you need to detect the all-branches mode;
   * `branchId` falls back to the user's pinned default for legacy
   * per-branch UIs.
   */
  sessionBranchId: string | null;
  userRecord: AuthUser | null;
  signUp: (email: string, password: string, metadata?: SignUpMetadata) => Promise<SignUpResult>;
  signIn: (email: string, password: string) => Promise<SignInResult>;
  signOut: () => Promise<void>;
  getCurrentUser: () => Promise<Pick<AuthUser, 'id' | 'email'> | null>;
  isEmailVerified: () => boolean;
  getUserProfile: () => Promise<AuthUser | null>;
  refreshUserRecord: () => Promise<void>;
  patchUserEmail: (email: string) => void;
}

const AuthContext = createContext<AuthContextType>({} as AuthContextType);

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

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
  const [user, setUser] = useState<Pick<AuthUser, 'id' | 'email'> | null>(null);
  const [session, setSession] = useState<AuthSession | null>(null);
  const [loading, setLoading] = useState(true);
  const [restaurantId, setRestaurantId] = useState<string | null>(null);
  const [branchId, setBranchId] = useState<string | null>(null);
  const [sessionBranchId, setSessionBranchId] = useState<string | null>(null);
  const [userRecord, setUserRecord] = useState<AuthUser | null>(null);
  const { syncUserLanguage } = useLanguage();

  const loadUser = useCallback(async () => {
    try {
      const res = await fetch('/api/auth/me');
      const data = (await res.json()) as { user: AuthUser | null };
      if (data.user) {
        setUser({ id: data.user.id, email: data.user.email });
        setSession({ user: data.user });
        setUserRecord(data.user);
        setRestaurantId(data.user.restaurant_id);
        setBranchId(data.user.branch_id);
        setSessionBranchId(data.user.session_branch_id ?? null);
        if (data.user.preferred_language) {
          syncUserLanguage(data.user.preferred_language);
        }
      } else {
        setUser(null);
        setSession(null);
        setUserRecord(null);
        setRestaurantId(null);
        setBranchId(null);
        setSessionBranchId(null);
      }
    } catch {
      setUser(null);
      setSession(null);
    } finally {
      setLoading(false);
    }
  }, [syncUserLanguage]);

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

  const signUp = async (
    email: string,
    password: string,
    metadata: SignUpMetadata = {}
  ): Promise<SignUpResult> => {
    const res = await fetch('/api/auth/sign-up', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        email,
        password,
        ownerName: metadata.ownerName,
        restaurantName: metadata.restaurantName,
        plan: metadata.plan,
      }),
    });
    const data = (await res.json()) as
      | { error?: string }
      | { requiresOtp: true; email: string }
      | { user: AuthUser };
    if (!res.ok) throw new Error(('error' in data && data.error) || 'Registration failed');
    if ('requiresOtp' in data && data.requiresOtp) {
      // Account not yet provisioned — caller should redirect to /verify-email
      return { requiresOtp: true, email: data.email };
    }
    const userPayload = (data as { user: AuthUser }).user;
    setUser({ id: userPayload.id, email: userPayload.email });
    setSession({ user: userPayload });
    setUserRecord(userPayload);
    setRestaurantId(userPayload.restaurant_id);
    setBranchId(userPayload.branch_id);
    setSessionBranchId(userPayload.session_branch_id ?? null);
    if (userPayload.preferred_language) syncUserLanguage(userPayload.preferred_language);
    return { user: userPayload, session: { user: userPayload } };
  };

  const signIn = async (email: string, password: string): Promise<SignInResult> => {
    const res = await fetch('/api/auth/sign-in', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password }),
    });
    const data = (await res.json()) as { error?: string; user?: AuthUser };
    if (!res.ok || !data.user) throw new Error(data.error || 'Invalid email or password');
    const userPayload = data.user;
    setUser({ id: userPayload.id, email: userPayload.email });
    setSession({ user: userPayload });
    setUserRecord(userPayload);
    setRestaurantId(userPayload.restaurant_id);
    setBranchId(userPayload.branch_id);
    setSessionBranchId(userPayload.session_branch_id ?? null);
    if (userPayload.preferred_language) syncUserLanguage(userPayload.preferred_language);
    // Refresh from /api/auth/me to pick up staff_permissions and any other
    // fields the sign-in response doesn't include (e.g. full restaurant
    // shape, currency_locked). We intentionally don't await — the initial
    // render uses the sign-in payload and the second pass (milliseconds
    // later) applies the enriched record including permission data.
    loadUser();
    return { user: userPayload, session: { user: userPayload } };
  };

  const signOut = async () => {
    await fetch('/api/auth/sign-out', { method: 'POST' });
    setUser(null);
    setSession(null);
    setUserRecord(null);
    setRestaurantId(null);
    setBranchId(null);
    setSessionBranchId(null);
    if (typeof window !== 'undefined') {
      window.location.href = '/login';
    }
  };

  const getCurrentUser = async () => user;
  const isEmailVerified = () => true;
  const getUserProfile = async () => userRecord;
  const refreshUserRecord = async () => { await loadUser(); };
  const patchUserEmail = (email: string) => {
    setUser(prev => prev ? { ...prev, email } : prev);
    setSession(prev => prev ? { user: { ...prev.user, email } } : prev);
    setUserRecord(prev => prev ? { ...prev, email } : prev);
  };

  const value: AuthContextType = {
    user,
    session,
    loading,
    restaurantId,
    branchId,
    sessionBranchId,
    userRecord,
    signUp,
    signIn,
    signOut,
    getCurrentUser,
    isEmailVerified,
    getUserProfile,
    refreshUserRecord,
    patchUserEmail,
  };

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