import React, { createContext, useState, useEffect, useContext } from 'react';
import { api } from '../utils/api';
import { AuthorModel } from '../types/models';
import { AuthContextModel } from '../types/contexts';

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

export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [currentUser, setCurrentUser] = useState<AuthorModel | null>(null);
  const [authors, setAuthors] = useState<AuthorModel[]>([]);
  const [token, setToken] = useState<string | null>(localStorage.getItem('token'));
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);

  /** 🔹 Register new user */
  const register = async (username: string, password: string) => {
    try {
      setLoading(true);
      setError(null);

      const res = await api.post('/auth/register', { username, password });
      return res.data; // returns PublicUser from the backend
    } catch (err: any) {
      console.error('Registration failed:', err);
      setError(err.response?.data?.detail || 'Registration failed');
    } finally {
      setLoading(false);
    }
  };

  /** 🔹 Login and store JWT token */
  const login = async (username: string, password: string) => {
    try {
      setLoading(true);
      setError(null);

      const res = await api.post('/auth/login', { username, password });
      const { access_token, user } = res.data;

      if (access_token) {
        localStorage.setItem('token', access_token);
        setToken(access_token);
        setCurrentUser(user);
      }
    } catch (err: any) {
      console.error('Login failed:', err);
      setError(err.response?.data?.detail || 'Invalid credentials');
    } finally {
      setLoading(false);
    }
  };

  /** 🔹 Logout and clear everything */
  const logout = () => {
    localStorage.removeItem('token');
    setToken(null);
    setCurrentUser(null);
    setAuthors([]);
  };

  /** 🔹 Fetch all authors (JWT handled by api interceptor) */
  const refreshAuthors = async () => {
    try {
      setLoading(true);
      setError(null);

      const res = await api.get<AuthorModel[]>('/authors');
      setAuthors(res.data);
    } catch (err: any) {
      console.error('Failed to fetch authors:', err);
      setError(err.response?.data?.detail || 'Failed to fetch authors');
    } finally {
      setLoading(false);
    }
  };

  /** 🔹 Update current user (full model) */
  const updateProfile = async (userData: AuthorModel) => {
    if (!userData._id) {
      console.error('updateProfile called without _id');
      return;
    }
    try {
      setLoading(true);
      setError(null);

      const res = await api.put<AuthorModel>(`/authors/${userData._id}`, userData);
      setCurrentUser(res.data);
      return res.data;
    } catch (err: any) {
      console.error('Profile update failed:', err);
      setError(err.response?.data?.detail || 'Failed to update profile');
    } finally {
      setLoading(false);
    }
  };


  /** 🔹 Auto-load current user if token exists */
  const fetchCurrentUser = async () => {
    if (!token) return;
    try {
      const me = await api.get<{ _id: string; username: string; email: string }>('/auth/me');

      const author = await api.get<AuthorModel>(`/authors/${me.data._id}`);

      const fullUser = { ...me.data, ...author.data };

      setCurrentUser(fullUser);
    } catch (err) {
      console.error('Failed to fetch current user:', err);
      logout();
    }
  };

  /** 🔹 On mount, try to fetch user if token exists */
  useEffect(() => {
    if (token) fetchCurrentUser();
  }, [token]);

  return (
    <AuthContext.Provider
      value={{
        currentUser,
        authors,
        token,
        loading,
        error,
        login,
        logout,
        register,
        refreshAuthors,
        updateProfile,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = (): AuthContextModel => {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be used inside AuthProvider');
  return ctx;
};
