'use client';

import { ClientUser } from "@/types/mutual/context/validations";
import { API_BASE_URL } from "@/config/config";
import { createContextHook } from '../hookFactory';
import { getUserFromServer, setUserFromServer } from '@/server/context/user';

// Constants
const FETCH_TIMEOUT = 5000; // 5 seconds timeout

// Default user state to use when API calls fail
const DEFAULT_USER_STATE: ClientUser = {
  uuid: 'default-user-id',
  avatar: '',
  email: '',
  phone_number: '',
  user_tag: 'guest',
  password_expiry_begins: new Date().toISOString(),
  person: {
    uuid: 'default-person-id',
    firstname: 'Guest',
    surname: 'User',
    middle_name: '',
    sex_code: '',
    person_tag: 'guest',
    country_code: '',
    birth_date: ''
  }
};

// Client-side fetch function that uses the server-side implementation
async function checkContextDashUserInfo(): Promise<ClientUser> {
  try {
    console.log('Fetching user data using server-side function');
    
    // First try to use the server-side implementation
    try {
      const serverData = await getUserFromServer();
      console.log('User data from server:', JSON.stringify(serverData, null, 2));
      
      // If we got valid data from the server, return it
      if (serverData && serverData.uuid) {
        // Check if we have a real user (not the default)
        if (serverData.uuid !== 'default-user-id' || 
            serverData.email || 
            (serverData.person && 
             (serverData.person.firstname !== 'Guest' || 
              serverData.person.surname !== 'User'))) {
          console.log('Valid user data found from server');
          return serverData;
        } else {
          console.log('Default user data returned from server, falling back to client-side');
        }
      } else {
        console.warn('Invalid user data structure from server');
      }
    } catch (serverError) {
      console.warn('Error using server-side user data fetch, falling back to client-side:', serverError);
      // Continue to client-side implementation
    }
    
    // Fall back to client-side implementation
    console.log(`Falling back to client-side fetch: ${API_BASE_URL}/context/dash/user`);
    
    // Create an AbortController to handle timeouts
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
    
    try {
      const result = await fetch(`${API_BASE_URL}/context/dash/user`, {
        method: "GET",
        headers: { 
          "Content-Type": "application/json",
          "Cache-Control": "no-cache"
        },
        signal: controller.signal
      });
      
      // Clear the timeout
      clearTimeout(timeoutId);
      
      if (!result.ok) {
        throw new Error(`HTTP error! Status: ${result.status}`);
      }
      
      const data = await result.json();
      console.log('User data API response:', data);
      
      // Handle different response formats
      if (data.status === 200 && data.data) {
        // Standard API response format
        return data.data;
      } else if (data.user) {
        // Direct Redis object format
        console.log('Found user data in Redis format');
        return data.user;
      } else if (data.uuid) {
        // Direct user object format
        console.log('Found direct user data format');
        return data;
      } else {
        console.warn('Invalid response format from user API');
        return DEFAULT_USER_STATE;
      }
    } catch (fetchError) {
      // Clear the timeout if it hasn't fired yet
      clearTimeout(timeoutId);
      
      // Check if this is an abort error (timeout)
      if (fetchError instanceof DOMException && fetchError.name === 'AbortError') {
        console.warn('Request timed out or was aborted');
        return DEFAULT_USER_STATE;
      }
      
      // Re-throw other errors to be caught by the outer catch
      throw fetchError;
    }
  } catch (error) {
    // Handle all other errors
    console.error('Error fetching user data:', error instanceof Error ? error.message : 'Unknown error');
    return DEFAULT_USER_STATE;
  }
}

async function setContextDashUserInfo({ userSet }: { userSet: ClientUser }): Promise<boolean> {
  try {
    console.log('Setting user data using server-side function');
    
    // First try to use the server-side implementation
    try {
      const success = await setUserFromServer(userSet);
      if (success) {
        console.log('Successfully updated user data using server-side function');
        return true;
      }
    } catch (serverError) {
      console.warn('Error using server-side user data update, falling back to client-side:', serverError);
      // Continue to client-side implementation
    }
    
    // Fall back to client-side implementation
    console.log(`Falling back to client-side update: ${API_BASE_URL}/context/dash/user`);
    
    // Create an AbortController to handle timeouts
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
    
    try {
      const result = await fetch(`${API_BASE_URL}/context/dash/user`, {
        method: "POST",
        headers: { 
          "Content-Type": "application/json",
          "Cache-Control": "no-cache"
        },
        body: JSON.stringify(userSet),
        signal: controller.signal
      });
      
      // Clear the timeout
      clearTimeout(timeoutId);
      
      if (!result.ok) {
        throw new Error(`HTTP error! Status: ${result.status}`);
      }
      
      const data = await result.json();
      console.log('Update user data API response:', data);
      
      return data.status === 200;
    } catch (fetchError) {
      // Clear the timeout if it hasn't fired yet
      clearTimeout(timeoutId);
      
      // Check if this is an abort error (timeout)
      if (fetchError instanceof DOMException && fetchError.name === 'AbortError') {
        console.warn('Request timed out or was aborted');
        return false;
      }
      
      // Re-throw other errors to be caught by the outer catch
      throw fetchError;
    }
  } catch (error) {
    console.error('Error setting user data:', error instanceof Error ? error.message : 'Unknown error');
    return false;
  }
}

// Create the user hook using the factory with custom fetch functions
const useContextUser = createContextHook<ClientUser>({
  endpoint: '/context/dash/user',
  contextName: 'user',
  enablePeriodicRefresh: false,
  // Use our improved fetch functions
  customFetch: checkContextDashUserInfo,
  customUpdate: async (newData: ClientUser) => {
    return await setContextDashUserInfo({ userSet: newData });
  },
  // Provide default value
  defaultValue: DEFAULT_USER_STATE
});

// Custom hook for user data with the expected interface
interface UseUserResult {
  userData: ClientUser | null;
  isLoading: boolean;
  error: string | null;
  refreshUser: () => Promise<void>;
  updateUser: (newUser: ClientUser) => Promise<boolean>;
}

// Wrapper hook that adapts the generic hook to the expected interface
export function useUser(): UseUserResult {
  const { data, isLoading, error, refresh, update } = useContextUser();
  
  return {
    userData: data,
    isLoading,
    error,
    refreshUser: refresh,
    updateUser: update
  };
}

export { checkContextDashUserInfo, setContextDashUserInfo };
