/**
 * Authentication Hooks
 * Custom hooks for authentication functionality
 */

"use client";

import { useCallback, useEffect, useRef } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useAuthStore } from "../stores/auth.store";
import { getPostLoginRedirect } from "@/features/auth/utils/route-protection";
import type { SignupRequest, LoginRequest, Permission } from "@customer-portal/domain/auth";
import {
  PERMISSIONS,
  hasPermission as checkPermission,
  hasAnyPermission as checkAnyPermission,
} from "@customer-portal/domain/auth";
import type { LogoutReason } from "@/features/auth/utils/logout-reason";

/**
 * Main authentication hook
 */
export function useAuth() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const {
    isAuthenticated,
    user,
    loading,
    hasCheckedAuth,
    error,
    login: loginAction,
    signup: signupAction,
    logout: logoutAction,
    requestPasswordReset,
    resetPassword,
    changePassword,
    checkPasswordNeeded,
    setPassword,
    checkAuth,
    refreshSession,
    clearError,
    clearLoading,
  } = useAuthStore();

  // Enhanced login with redirect handling
  const login = useCallback(
    async (credentials: LoginRequest, options?: { redirectTo?: string }) => {
      await loginAction(credentials);
      // Keep loading state active during redirect
      const redirectTo = getPostLoginRedirect(searchParams, options?.redirectTo);
      router.push(redirectTo);
      // Note: loading will be cleared when the new page loads
    },
    [loginAction, router, searchParams]
  );

  // Enhanced signup with redirect handling
  const signup = useCallback(
    async (data: SignupRequest, options?: { redirectTo?: string }) => {
      await signupAction(data);
      const dest = getPostLoginRedirect(searchParams, options?.redirectTo);
      router.push(dest);
    },
    [signupAction, router, searchParams]
  );

  // Enhanced logout with redirect
  const logout = useCallback(
    async (options?: { reason?: LogoutReason }) => {
      const reason = options?.reason ?? ("manual" as const);
      await logoutAction({ reason });
      const reasonQuery = reason ? `?reason=${reason}` : "";
      router.push(`/auth/login${reasonQuery}`);
    },
    [logoutAction, router]
  );

  return {
    // State
    isAuthenticated,
    user,
    loading,
    hasCheckedAuth,
    error,

    // Actions
    login,
    signup,
    logout,
    requestPasswordReset,
    resetPassword,
    changePassword,
    checkPasswordNeeded,
    setPassword,
    checkAuth,
    refreshSession,
    clearError,
    clearLoading,
  };
}

/**
 * Hook for login functionality (legacy - direct login)
 * @deprecated Use useLoginWithOtp for two-step OTP login flow
 */
export function useLogin(options?: { redirectTo?: string } | undefined) {
  const { login, loading, error, clearError } = useAuth();

  return {
    login: (credentials: LoginRequest) =>
      login(credentials, options?.redirectTo ? { redirectTo: options.redirectTo } : undefined),
    loading,
    error,
    clearError,
  };
}

/**
 * Hook for two-step OTP login flow
 *
 * Step 1: initiateLogin - validates credentials, sends OTP
 * Step 2: verifyOtp - verifies OTP and completes login
 */
export function useLoginWithOtp(options?: { redirectTo?: string } | undefined) {
  const router = useRouter();
  const searchParams = useSearchParams();
  const { initiateLogin, verifyLoginOtp, loading, error, clearError } = useAuthStore();

  const handleInitiateLogin = useCallback(
    async (credentials: LoginRequest) => {
      return await initiateLogin(credentials);
    },
    [initiateLogin]
  );

  const handleVerifyOtp = useCallback(
    async (sessionToken: string, code: string, rememberDevice?: boolean) => {
      await verifyLoginOtp(sessionToken, code, rememberDevice);
      // Login successful - redirect
      const redirectTo = getPostLoginRedirect(searchParams, options?.redirectTo);
      router.push(redirectTo);
    },
    [verifyLoginOtp, router, searchParams, options?.redirectTo]
  );

  return {
    initiateLogin: handleInitiateLogin,
    verifyOtp: handleVerifyOtp,
    loading,
    error,
    clearError,
  };
}

/**
 * Hook for signup functionality
 */
export function useSignup() {
  return useSignupWithRedirect();
}

export function useSignupWithRedirect(options?: { redirectTo?: string } | undefined) {
  const { signup, loading, error, clearError } = useAuth();

  return {
    signup: (data: SignupRequest) =>
      signup(data, options?.redirectTo ? { redirectTo: options.redirectTo } : undefined),
    loading,
    error,
    clearError,
  };
}

/**
 * Hook for password reset functionality
 */
export function usePasswordReset() {
  const { requestPasswordReset, resetPassword, loading, error, clearError } = useAuth();

  return {
    requestPasswordReset,
    resetPassword,
    loading,
    error,
    clearError,
  };
}

/**
 * Hook for password change functionality
 */
export function usePasswordChange() {
  const { changePassword, loading, error, clearError } = useAuth();

  return {
    changePassword,
    loading,
    error,
    clearError,
  };
}

/**
 * Hook for session management
 *
 * Refresh strategy (to avoid rate limits):
 * - On mount: check auth once
 * - Periodically: check every 4 minutes (the store will only actually refresh if token is expiring)
 * - On tab focus: check once (the store will skip if token is still fresh)
 *
 * The actual decision to call the refresh API is made in the auth store based on token expiry.
 */
export function useSession() {
  const isAuthenticated = useAuthStore(state => state.isAuthenticated);
  const user = useAuthStore(state => state.user);
  const hasCheckedAuth = useAuthStore(state => state.hasCheckedAuth);
  const checkAuth = useAuthStore(state => state.checkAuth);
  const refreshSession = useAuthStore(state => state.refreshSession);
  const logout = useAuthStore(state => state.logout);

  // Track if we've initiated auth check to prevent duplicate calls
  const authCheckInitiated = useRef(false);

  // Auto-check auth on mount - only once
  useEffect(() => {
    if (!hasCheckedAuth && !authCheckInitiated.current) {
      authCheckInitiated.current = true;
      void checkAuth();
    }
  }, [hasCheckedAuth, checkAuth]);

  // Periodic refresh check - the store will only actually refresh if token is expiring soon
  useEffect(() => {
    if (!isAuthenticated) {
      return;
    }

    const interval = setInterval(
      () => {
        void refreshSession();
      },
      4 * 60 * 1000
    ); // Check every 4 minutes (store decides if refresh is needed)

    return () => clearInterval(interval);
  }, [isAuthenticated, refreshSession]);

  // Refresh on tab visibility - the store will skip if token is still fresh
  useEffect(() => {
    if (!isAuthenticated || typeof window === "undefined") {
      return;
    }

    const handleVisibility = () => {
      if (document.visibilityState === "visible") {
        // The store will only refresh if the token is expiring soon
        void refreshSession();
      }
    };

    document.addEventListener("visibilitychange", handleVisibility);

    return () => {
      document.removeEventListener("visibilitychange", handleVisibility);
    };
  }, [isAuthenticated, refreshSession]);

  return {
    isAuthenticated,
    user,
    checkAuth,
    refreshSession,
    logout,
  };
}

/**
 * Hook for user profile information
 */
export function useUser() {
  const { user, isAuthenticated } = useAuth();

  const fullName = user ? `${user.firstname || ""} ${user.lastname || ""}`.trim() : "";
  const initials = user
    ? `${user.firstname?.[0] || ""}${user.lastname?.[0] || ""}`.toUpperCase()
    : "";

  return {
    user,
    isAuthenticated,
    fullName,
    initials,
    email: user?.email,
    company: user?.companyname,
    phone: user?.phonenumber,
    avatar: undefined, // Not in current schema
    preferences: undefined, // Not in current schema
  };
}

/**
 * Hook for checking user permissions
 */
export function usePermissions() {
  const { user } = useAuth();
  const role = user?.role ?? "USER";

  const hasRole = useCallback(
    (targetRole: string) => {
      if (!user?.role) return false;
      return user.role === targetRole;
    },
    [user?.role]
  );

  const hasAnyRole = useCallback(
    (roles: string[]) => roles.some(targetRole => hasRole(targetRole)),
    [hasRole]
  );

  const hasPermission = useCallback(
    (permission: Permission) => checkPermission(role, permission),
    [role]
  );

  const hasAnyPermission = useCallback(
    (permissions: Permission[]) => checkAnyPermission(role, permissions),
    [role]
  );

  return {
    role: user?.role,
    permissions: PERMISSIONS,
    hasRole,
    hasAnyRole,
    hasPermission,
    hasAnyPermission,
  };
}
