import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from 'react';
import { apiAuth } from '../api';

export interface StaffUser {
  id: number;
  email: string;
  fullName: string;
  mustChangePassword: boolean;
}

interface AuthState {
  token: string | null;
  staff: StaffUser | null;
  loading: boolean;
  login: (email: string, password: string) => Promise<void>;
  provision: (email: string) => Promise<string>;
  logout: () => void;
  changePassword: (oldPassword: string, newPassword: string) => Promise<void>;
  forgotPassword: (email: string) => Promise<string>;
  resetPassword: (token: string, newPassword: string) => Promise<void>;
  refreshMe: () => Promise<void>;
}

const TOKEN_KEY = 'sc_staff_token';
const AuthContext = createContext<AuthState | null>(null);

export function AuthProvider({ children }: { children: ReactNode }) {
  const [token, setToken] = useState<string | null>(() => localStorage.getItem(TOKEN_KEY));
  const [staff, setStaff] = useState<StaffUser | null>(null);
  const [loading, setLoading] = useState(true);

  const applySession = useCallback((nextToken: string | null, nextStaff: StaffUser | null) => {
    setToken(nextToken);
    setStaff(nextStaff);
    if (nextToken) {
      localStorage.setItem(TOKEN_KEY, nextToken);
    } else {
      localStorage.removeItem(TOKEN_KEY);
    }
  }, []);

  const refreshMe = useCallback(async () => {
    if (!token) {
      setStaff(null);
      setLoading(false);
      return;
    }
    try {
      const res = await apiAuth.me();
      setStaff(res.staff);
    } catch {
      applySession(null, null);
    } finally {
      setLoading(false);
    }
  }, [token, applySession]);

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

  const login = useCallback(async (email: string, password: string) => {
    const res = await apiAuth.login(email, password);
    applySession(res.token, res.staff);
  }, [applySession]);

  const provision = useCallback(async (email: string) => {
    const res = await apiAuth.provision(email);
    return res.message;
  }, []);

  const logout = useCallback(() => {
    applySession(null, null);
  }, [applySession]);

  const changePassword = useCallback(async (oldPassword: string, newPassword: string) => {
    const res = await apiAuth.changePassword(oldPassword, newPassword);
    applySession(res.token, res.staff);
  }, [applySession]);

  const forgotPassword = useCallback(async (email: string) => {
    const res = await apiAuth.forgotPassword(email);
    return res.message;
  }, []);

  const resetPassword = useCallback(async (resetToken: string, newPassword: string) => {
    await apiAuth.resetPassword(resetToken, newPassword);
  }, []);

  const value = useMemo<AuthState>(() => ({
    token,
    staff,
    loading,
    login,
    provision,
    logout,
    changePassword,
    forgotPassword,
    resetPassword,
    refreshMe,
  }), [token, staff, loading, login, provision, logout, changePassword, forgotPassword, resetPassword, refreshMe]);

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

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

export function getStoredToken(): string | null {
  return localStorage.getItem(TOKEN_KEY);
}
