import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { api, registerAuthCallbacks } from '@/lib/api';
import type { User, AuthResponse } from '@/types/api';

interface AuthState {
  user: User | null;
  accessToken: string | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  error: string | null;
  errorCode: string | null;
  registrationMessage: string | null;
}

interface AuthActions {
  login: (email: string, password: string) => Promise<void>;
  register: (name: string, email: string, password: string, inviteCode?: string) => Promise<{ requiresVerification?: boolean }>;
  logout: () => Promise<void>;
  refresh: () => Promise<void>;
  fetchMe: () => Promise<void>;
  hydrate: () => Promise<void>;
  setAccessToken: (accessToken: string) => void;
  clearAuth: () => void;
  clearError: () => void;
}

export const useAuthStore = create<AuthState & AuthActions>()(
  persist(
    (set, get) => ({
      user: null,
      accessToken: null,
      isAuthenticated: false,
      isLoading: true,
      error: null,
      errorCode: null,
      registrationMessage: null,

      login: async (email: string, password: string) => {
        set({ error: null, errorCode: null, isLoading: true, registrationMessage: null });
        try {
          // Refresh token is set as httpOnly cookie by the server (not in response body)
          const { data } = await api.post<AuthResponse>('/auth/login', {
            email,
            password,
          });
          set({
            user: data.user,
            accessToken: data.accessToken || null,
            isAuthenticated: true,
            isLoading: false,
          });
        } catch (err: unknown) {
          const resp = (err as { response?: { data?: { error?: { message?: string; code?: string } } } })?.response?.data?.error;
          const message = resp?.message || 'Login failed';
          const code = resp?.code || null;
          set({ error: message, errorCode: code, isLoading: false });
          throw err;
        }
      },

      register: async (name: string, email: string, password: string, inviteCode?: string) => {
        set({ error: null, errorCode: null, isLoading: true, registrationMessage: null });
        try {
          const { data } = await api.post<AuthResponse>('/auth/register', {
            name,
            email,
            password,
            ...(inviteCode ? { inviteCode } : {}),
          });

          // If verification is required, don't set tokens — user needs to verify email first
          if (data.requiresVerification) {
            set({
              isLoading: false,
              registrationMessage: data.message || 'Please check your email to verify your account',
            });
            return { requiresVerification: true };
          }

          set({
            user: data.user,
            accessToken: data.accessToken || null,
            isAuthenticated: true,
            isLoading: false,
          });
          return {};
        } catch (err: unknown) {
          const resp = (err as { response?: { data?: { error?: { message?: string; code?: string } } } })?.response?.data?.error;
          const message = resp?.message || 'Registration failed';
          const code = resp?.code || null;
          set({ error: message, errorCode: code, isLoading: false });
          throw err;
        }
      },

      logout: async () => {
        try {
          // Refresh token sent automatically as httpOnly cookie
          await api.post('/auth/logout');
        } catch {
          // Ignore logout errors
        }
        get().clearAuth();
      },

      refresh: async () => {
        try {
          // Refresh token sent automatically as httpOnly cookie
          const { data } = await api.post<AuthResponse>('/auth/refresh');
          set({
            user: data.user,
            accessToken: data.accessToken || null,
            isAuthenticated: true,
          });
        } catch {
          get().clearAuth();
        }
      },

      fetchMe: async () => {
        try {
          const { data } = await api.get<User>('/auth/me');
          set({ user: data, isAuthenticated: true, isLoading: false });
        } catch (err: unknown) {
          // Suppress console logging for expected 401 errors (unauthenticated users)
          const is401 = (err as { response?: { status?: number } })?.response?.status === 401;
          if (!is401) {
            console.error('Unexpected auth error:', err);
          }
          get().clearAuth();
        }
      },

      hydrate: async () => {
        // Always attempt to restore session via httpOnly refresh cookie.
        // Access token is no longer persisted to localStorage (XSS protection).
        try {
          const { data } = await api.post<AuthResponse>('/auth/refresh');
          set({
            accessToken: data.accessToken || null,
            user: data.user,
            isAuthenticated: true,
            isLoading: false,
          });
        } catch {
          // No valid refresh cookie — user is not logged in
          set({ isLoading: false });
        }
      },

      setAccessToken: (accessToken: string) => {
        set({ accessToken });
      },

      clearAuth: () => {
        set({
          user: null,
          accessToken: null,
          isAuthenticated: false,
          isLoading: false,
          error: null,
          errorCode: null,
          registrationMessage: null,
        });
      },

      clearError: () => {
        set({ error: null, errorCode: null, registrationMessage: null });
      },
    }),
    {
      name: 'cml-auth',
      // Do not persist accessToken to localStorage — XSS could steal it.
      // Session is restored via httpOnly refresh cookie in hydrate().
      partialize: () => ({}),
    }
  )
);

// Register callbacks for the API interceptor (breaks circular dependency)
registerAuthCallbacks({
  getAccessToken: () => useAuthStore.getState().accessToken,
  onTokenRefresh: (accessToken) => {
    useAuthStore.getState().setAccessToken(accessToken);
  },
  onAuthFailure: () => {
    useAuthStore.getState().clearAuth();
    window.location.href = '/login';
  },
});
