'use client';

import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { useRouter } from 'next/navigation';
import apiClient from '@/lib/api/client';
import { tokenStorage } from '@/lib/utils/tokenStorage';

export interface User {
  id: string;
  email: string;
  name: string;
  role: string;
  families?: Array<{
    id: string;
    familyId: string;
    role: string;
  }>;
}

export interface LoginCredentials {
  email: string;
  password: string;
  deviceFingerprint?: string;
}

export interface RegisterData {
  email: string;
  password: string;
  name: string;
  role?: string;
}

interface AuthContextType {
  user: User | null;
  token: string | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  login: (credentials: LoginCredentials) => Promise<void>;
  register: (data: RegisterData) => Promise<void>;
  logout: () => Promise<void>;
  refreshUser: () => Promise<void>;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [user, setUser] = useState<User | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const router = useRouter();

  const isAuthenticated = !!user;

  // Check authentication status on mount
  useEffect(() => {
    // Only run on client side
    if (typeof window !== 'undefined') {
      checkAuth();
    } else {
      setIsLoading(false);
    }
  }, []);

  const checkAuth = async () => {
    // Ensure we're on client side
    if (typeof window === 'undefined') {
      setIsLoading(false);
      return;
    }

    try {
      const accessToken = tokenStorage.getAccessToken();
      if (!accessToken) {
        setIsLoading(false);
        return;
      }

      // Set token in state
      setToken(accessToken);

      const response = await apiClient.get('/api/v1/auth/me');

      // Check if response has expected structure
      if (response.data?.data) {
        setUser(response.data.data);
      } else if (response.data?.user) {
        // Handle alternative response structure
        setUser(response.data.user);
      } else {
        throw new Error('Invalid response structure');
      }
    } catch (error: any) {
      console.error('Auth check failed:', error);
      // Only clear tokens if it's an actual auth error (401, 403)
      if (error?.response?.status === 401 || error?.response?.status === 403) {
        tokenStorage.clearTokens();
        setUser(null);
        setToken(null);
      }
    } finally {
      setIsLoading(false);
    }
  };

  const login = async (credentials: LoginCredentials) => {
    try {
      const deviceInfo = {
        deviceId: generateDeviceFingerprint(),
        platform: 'web',
        model: navigator.userAgent,
        osVersion: navigator.platform,
      };

      const response = await apiClient.post('/api/v1/auth/login', {
        email: credentials.email,
        password: credentials.password,
        deviceInfo,
      });

      // Backend returns { success, data: { user, tokens } }
      const { data: responseData } = response.data;
      const { tokens, user: userData } = responseData;

      tokenStorage.setTokens(tokens.accessToken, tokens.refreshToken);
      setToken(tokens.accessToken);
      setUser(userData);

      router.push('/');
    } catch (error: any) {
      console.error('Login failed:', error);
      throw new Error(error.response?.data?.message || 'Login failed');
    }
  };

  const register = async (data: RegisterData) => {
    try {
      const deviceInfo = {
        deviceId: generateDeviceFingerprint(),
        platform: 'web',
        model: navigator.userAgent,
        osVersion: navigator.platform,
      };

      const response = await apiClient.post('/api/v1/auth/register', {
        email: data.email,
        password: data.password,
        name: data.name,
        deviceInfo,
      });

      // Backend returns { success, data: { user, family, tokens } }
      const { data: responseData } = response.data;
      const { tokens, user: userData } = responseData;

      if (!tokens?.accessToken || !tokens?.refreshToken) {
        throw new Error('Invalid response from server');
      }

      const { accessToken, refreshToken } = tokens;

      tokenStorage.setTokens(accessToken, refreshToken);
      setToken(accessToken);
      setUser(userData);

      // Redirect to onboarding
      router.push('/onboarding');
    } catch (error: any) {
      console.error('Registration failed:', error);
      throw new Error(error.response?.data?.message || error.message || 'Registration failed');
    }
  };

  const logout = async () => {
    try {
      await apiClient.post('/api/v1/auth/logout');
    } catch (error) {
      console.error('Logout failed:', error);
    } finally {
      tokenStorage.clearTokens();
      setUser(null);
      setToken(null);
      router.push('/login');
    }
  };

  const refreshUser = async () => {
    try {
      const response = await apiClient.get('/api/v1/auth/me');
      setUser(response.data.data);
    } catch (error) {
      console.error('Failed to refresh user:', error);
    }
  };

  return (
    <AuthContext.Provider
      value={{
        user,
        token,
        isLoading,
        isAuthenticated,
        login,
        register,
        logout,
        refreshUser,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

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

// Helper function to generate a simple device fingerprint
function generateDeviceFingerprint(): string {
  const navigator = window.navigator;
  const screen = window.screen;

  const data = [
    navigator.userAgent,
    navigator.language,
    screen.colorDepth,
    screen.width,
    screen.height,
    new Date().getTimezoneOffset(),
  ].join('|');

  // Simple hash function
  let hash = 0;
  for (let i = 0; i < data.length; i++) {
    const char = data.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash;
  }

  return hash.toString(36);
}
