import { useState, useEffect, useCallback, useRef } from 'react';
import { clientPortalApi } from '@/lib/api/clientPortalApi';

// 👇 NEW — how often to refresh the access token (13 min, safely before 15-min expiry)
const REFRESH_INTERVAL_MS = 13 * 60 * 1000; // 13 minutes
// 👇 NEW — how often the checker wakes up (every 60s)
const REFRESH_CHECK_MS = 60 * 1000; // 1 minute

export function useClientAuth() {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [email, setEmail] = useState('');
  const [stage, setStage] = useState<'email' | 'otp' | 'verified'>('email');
  const [token, setToken] = useState('');
  const [user, setUser] = useState(null);
  const [otpSent, setOtpSent] = useState(false);

  // 👇 NEW — refs for the refresh timer (won't trigger re-renders)
  const lastRefreshRef = useRef<number>(Date.now());
  const refreshCheckerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const isRefreshingRef = useRef<boolean>(false);

  // ═══════════════════════════════════════════════════════════════════
  // 👇 NEW — LOGOUT: clears all tokens and redirects to login
  // ═══════════════════════════════════════════════════════════════════
  const forceLogout = useCallback((reason?: string) => {
    try {
      localStorage.removeItem('clientPortalToken');
      localStorage.removeItem('clientPortalRefreshToken');
      localStorage.removeItem('clientUser');
    } catch { /* ignore */ }
    setToken('');
    setUser(null);
    setStage('email');
    setOtpSent(false);
    if (reason) setError(reason);
    if (
      typeof window !== 'undefined' &&
      !window.location.pathname.includes('/login')
    ) {
      window.location.href = '/login';
    }
  }, []);

  // ═══════════════════════════════════════════════════════════════════
  // 👇 NEW — SILENT REFRESH: get a new access token using the refresh token.
  //         Handles the "portal disabled" case → IMMEDIATE logout.
  // ═══════════════════════════════════════════════════════════════════
  const refreshAccessToken = useCallback(async (): Promise<boolean> => {
    if (isRefreshingRef.current) return true; // guard against parallel calls
    isRefreshingRef.current = true;

    try {
      const refreshToken = localStorage.getItem('clientPortalRefreshToken');
      if (!refreshToken) return false;

      const response = await clientPortalApi.refreshToken(refreshToken);
      const data = response?.data || response;
      const newAccessToken = data?.access_token || response?.access_token;

      if (response?.success && newAccessToken) {
        localStorage.setItem('clientPortalToken', newAccessToken);
        setToken(newAccessToken);
        lastRefreshRef.current = Date.now();
        console.log('[AUTH] ✓ Access token refreshed silently');
        return true;
      }

      // Refresh rejected — check reason to decide message
      const errorMsg = String(
        data?.message || response?.message || '',
      ).toLowerCase();
      if (errorMsg.includes('disabled') || errorMsg.includes('deactivat')) {
        console.warn('[AUTH] ⚠️ Portal access DISABLED — forcing logout');
        forceLogout('Your portal access has been disabled by the administrator.');
      } else {
        console.warn('[AUTH] ⚠️ Refresh failed — forcing re-login');
        forceLogout('Your session has expired. Please log in again.');
      }
      return false;
    } catch (err: any) {
      const status = err?.response?.status || err?.status;
      const bodyMsg = String(
        err?.response?.data?.message || err?.message || '',
      ).toLowerCase();

      if (status === 401 || status === 403) {
        if (bodyMsg.includes('disabled') || bodyMsg.includes('deactivat')) {
          forceLogout('Your portal access has been disabled by the administrator.');
        } else {
          forceLogout('Your session has expired. Please log in again.');
        }
      } else {
        // Network error — don't logout, just log & retry later
        console.warn('[AUTH] Refresh network error (will retry):', err);
      }
      return false;
    } finally {
      isRefreshingRef.current = false;
    }
  }, [forceLogout]);

  // ═══════════════════════════════════════════════════════════════════
  // 👇 NEW — AUTO-REFRESH TIMER: refreshes every 13 minutes while logged in.
  //         Also refreshes when tab regains focus (survives browser sleep).
  // ═══════════════════════════════════════════════════════════════════
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const hasRefresh = !!localStorage.getItem('clientPortalRefreshToken');
    if (!hasRefresh) return;

    const check = () => {
      const elapsed = Date.now() - lastRefreshRef.current;
      if (elapsed >= REFRESH_INTERVAL_MS) refreshAccessToken();
    };

    refreshCheckerRef.current = setInterval(check, REFRESH_CHECK_MS);

    const onFocus = () => {
      const elapsed = Date.now() - lastRefreshRef.current;
      if (elapsed >= REFRESH_INTERVAL_MS) refreshAccessToken();
    };
    window.addEventListener('focus', onFocus);

    return () => {
      if (refreshCheckerRef.current) clearInterval(refreshCheckerRef.current);
      window.removeEventListener('focus', onFocus);
    };
  }, [refreshAccessToken, token]);

  // ═══════════════════════════════════════════════════════════════════
  // 👇 NEW — HYDRATE from localStorage on mount (survives page refresh)
  // ═══════════════════════════════════════════════════════════════════
  useEffect(() => {
    if (typeof window === 'undefined') return;
    try {
      const savedToken = localStorage.getItem('clientPortalToken');
      const savedUser = localStorage.getItem('clientUser');
      if (savedToken) {
        setToken(savedToken);
        setStage('verified');
        if (savedUser) setUser(JSON.parse(savedUser));
      }
    } catch { /* ignore */ }
  }, []);

  const requestOtp = async (clientEmail: string, inviteToken?: string) => {
    setLoading(true);
    setError(null);
    try {
      const response = await clientPortalApi.login(clientEmail, inviteToken);
      const data = response.data || response;
      const otpSentFlag = data.otp_sent || response.otp_sent;
      
      if (response.success && otpSentFlag) {
        setEmail(clientEmail);
        setStage('otp');
        setOtpSent(true);
        return { 
          success: true, 
          message: data.message || response.message, 
          expiresIn: data.expires_in_minutes || response.expires_in_minutes || 10 
        };
      } else {
        const errorMsg = data.message || response.message || 'Failed to send OTP';
        setError(errorMsg);
        return { success: false, message: errorMsg };
      }
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'An error occurred';
      setError(errorMsg);
      return { success: false, message: errorMsg };
    } finally {
      setLoading(false);
    }
  };

  const verifyOtp = async (otpCode: string) => {
    setLoading(true);
    setError(null);
    try {
      const response = await clientPortalApi.verifyOtp(email, otpCode);
      const data = response.data || response;
      const accessToken = data.access_token || response.access_token;
      // 👇 NEW — capture the refresh token (was thrown away before!)
      const refreshToken = data.refresh_token || response.refresh_token;
      
      if (response.success && accessToken) {
        localStorage.setItem('clientPortalToken', accessToken);
        localStorage.setItem('clientUser', JSON.stringify(data.user || response.user));
        // 👇 NEW — persist refresh token so auto-refresh works across page reloads
        if (refreshToken) {
          localStorage.setItem('clientPortalRefreshToken', refreshToken);
        }
        // 👇 NEW — reset the refresh timer clock
        lastRefreshRef.current = Date.now();

        setToken(accessToken);
        setUser(data.user || response.user);
        setStage('verified');
        return { 
          success: true, 
          message: data.message || response.message, 
          user: data.user || response.user, 
          token: accessToken 
        };
      } else {
        const errorMsg = data.message || response.message || 'OTP verification failed';
        setError(errorMsg);
        return { success: false, message: errorMsg };
      }
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'An error occurred';
      setError(errorMsg);
      return { success: false, message: errorMsg };
    } finally {
      setLoading(false);
    }
  };

  const resendOtp = async (inviteToken: string) => {
    setLoading(true);
    setError(null);
    try {
      const response = await clientPortalApi.login(email, inviteToken);
      const data = response.data || response;
      const otpSentFlag = data.otp_sent || response.otp_sent;
      
      if (response.success && otpSentFlag) {
        return { 
          success: true, 
          message: data.message || response.message 
        };
      } else {
        const errorMsg = data.message || response.message || 'Failed to resend OTP';
        setError(errorMsg);
        return { success: false, message: errorMsg };
      }
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'An error occurred';
      setError(errorMsg);
      return { success: false, message: errorMsg };
    } finally {
      setLoading(false);
    }
  };

  // 🆕 NEW — sync hook state to 'otp' stage WITHOUT calling the API again.
  //         Used by the invite-token auto-detect flow, where the initial
  //         /login call already sent the OTP. Prevents the "2 OTP emails"
  //         bug caused by calling requestOtp() after the invite-token
  //         validation already triggered a send.
  const markOtpSent = (clientEmail: string) => {
    setEmail(clientEmail);
    setStage('otp');
    setOtpSent(true);
    setError(null);
  };

  return {
    loading,
    error,
    email,
    stage,
    token,
    user,
    otpSent,
    requestOtp,
    verifyOtp,
    resendOtp,
    markOtpSent,   // 🆕 exposed
    setError,
    // 👇 NEW — exposed so components can manually trigger refresh or logout
    refreshAccessToken,
    forceLogout,
  };
}