// File: src/hocs/withPasswordProtection.jsx
// Enhanced HOC with password expiry event handling and session expired page redirect
import React, { useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router";

/**
 * HOC that protects components by checking if password is available
 * Enhanced with password expiry event handling and better UX for session expiry
 * FIXED: Safely handles ServiceProvider context availability
 */
const withPasswordProtection = (WrappedComponent, options = {}) => {
  const {
    redirectTo = "/login",
    sessionExpiredRedirectTo = "/session-expired", // NEW: Dedicated session expired page
    showLoadingWhileChecking = true,
    checkInterval = null,
    customMessage = "Password required. Redirecting to login...",
    onPasswordExpired = null, // Callback when password expires
  } = options;

  const PasswordProtectedComponent = (props) => {
    const navigate = useNavigate();
    const location = useLocation();

    // 🔧 FIXED: Safely access services with fallback
    const [servicesAvailable, setServicesAvailable] = useState(false);
    const [passwordStorageService, setPasswordStorageService] = useState(null);
    const [isChecking, setIsChecking] = useState(true);
    const [hasPassword, setHasPassword] = useState(false);
    const [expiryMessage, setExpiryMessage] = useState("");
    const [showExpiryModal, setShowExpiryModal] = useState(false);
    const [expiryReason, setExpiryReason] = useState("");

    // 🔧 NEW: Initialize services safely
    useEffect(() => {
      const initializeServices = async () => {
        try {
          // Try to import services safely
          const { useStorage } = await import("../services/Services");

          // Check if we're in a ServiceProvider context
          if (window.mapleopentechServices?.passwordStorageService) {
            setPasswordStorageService(
              window.mapleopentechServices.passwordStorageService,
            );
            setServicesAvailable(true);
            console.log(
              "[withPasswordProtection] Services initialized via window.mapleopentechServices",
            );
          } else {
            // Try React context (but this might fail if outside provider)
            try {
              const services = useStorage();
              setPasswordStorageService(services.passwordStorageService);
              setServicesAvailable(true);
              console.log(
                "[withPasswordProtection] Services initialized via React context",
              );
            } catch (contextError) {
              console.warn(
                "[withPasswordProtection] React context not available:",
                contextError.message,
              );

              // Fallback: Try to get services directly
              try {
                const { default: passwordStorageService } =
                  await import("../services/PasswordStorageService.js");
                setPasswordStorageService(passwordStorageService);
                setServicesAvailable(true);
                console.log(
                  "[withPasswordProtection] Services initialized via direct import",
                );
              } catch (importError) {
                console.error(
                  "[withPasswordProtection] Failed to initialize services:",
                  importError,
                );
                // Still allow the component to render, but it will redirect to login
                setServicesAvailable(false);
              }
            }
          }
        } catch (error) {
          console.error(
            "[withPasswordProtection] Error initializing services:",
            error,
          );
          setServicesAvailable(false);
        }
      };

      initializeServices();
    }, []);

    useEffect(() => {
      let mounted = true;
      let intervalId = null;

      // Only proceed if services are available
      if (!servicesAvailable || !passwordStorageService) {
        return;
      }

      // ENHANCED: Listen for password expiry events
      const handlePasswordExpired = (event) => {
        console.log(
          "[withPasswordProtection] Password expired event received:",
          event.detail,
        );

        if (!mounted) return;

        const reason = event.detail?.reason || "unknown";
        let message = "Session expired - please log in again";

        switch (reason) {
          case "inactivity_timeout":
            message = "Session expired due to inactivity - please log in again";
            break;
          case "manual_clear":
            message = "Session cleared - please log in again";
            break;
          case "token_refresh_failed":
            message =
              event.detail?.message ||
              "Your authentication tokens expired and could not be refreshed - please log in again";
            break;
          default:
            message =
              event.detail?.message || "Session expired - please log in again";
        }

        setExpiryMessage(message);
        setExpiryReason(reason);
        setHasPassword(false);
        setShowExpiryModal(true);

        // Call custom callback if provided
        if (onPasswordExpired) {
          try {
            onPasswordExpired(reason, message);
          } catch (error) {
            console.error(
              "[withPasswordProtection] Error in onPasswordExpired callback:",
              error,
            );
          }
        }

        // Modal will handle the redirect when user clicks the button
        console.log(
          `[withPasswordProtection] Showing expiry modal due to: ${reason}`,
        );
      };

      // Add password expiry event listener
      window.addEventListener("passwordExpired", handlePasswordExpired);

      const checkPasswordAsync = async () => {
        console.log(
          `[withPasswordProtection] Starting password check for ${location.pathname}`,
        );

        // Check authentication first if authManager is available
        let authManager = null;
        if (window.mapleopentechServices?.authManager) {
          authManager = window.mapleopentechServices.authManager;
          console.log(
            "[withPasswordProtection] Found authManager from unified services",
          );
        }

        // Check authentication first if authManager is available
        if (authManager && typeof authManager.isAuthenticated === "function") {
          try {
            const isAuthenticated = authManager.isAuthenticated();
            console.log(
              "[withPasswordProtection] Authentication status:",
              isAuthenticated,
            );

            if (!isAuthenticated) {
              console.log(
                "[withPasswordProtection] User not authenticated, redirecting to login",
              );
              if (mounted) {
                navigate(redirectTo, {
                  state: {
                    from: location,
                    message: "Please log in to access this page",
                  },
                  replace: true,
                });
              }
              return false;
            }
          } catch (error) {
            console.warn(
              "[withPasswordProtection] Error checking authentication:",
              error,
            );
          }
        }

        // Wait a bit for service initialization if needed
        if (!passwordStorageService.isInitialized) {
          console.log(
            "[withPasswordProtection] Waiting for service initialization...",
          );
          await new Promise((resolve) => setTimeout(resolve, 100));
        }

        // In development with localStorage, explicitly try to restore
        const storageInfo = passwordStorageService.getStorageInfo();
        if (storageInfo.isDevelopment && storageInfo.mode === "localStorage") {
          console.log(
            "[withPasswordProtection] Dev mode detected, attempting restore...",
          );

          // Give the service a chance to restore from localStorage
          if (!passwordStorageService.password) {
            try {
              const restored =
                await passwordStorageService.restorePasswordFromStorage();
              console.log(
                "[withPasswordProtection] Restore attempt result:",
                restored,
              );
            } catch (error) {
              console.error("[withPasswordProtection] Restore error:", error);
            }
          }
        }

        // Now check for password
        const passwordAvailable = passwordStorageService.hasPassword();
        console.log(
          `[withPasswordProtection] Password check result for ${location.pathname}:`,
          passwordAvailable,
        );
        console.log(
          `[withPasswordProtection] Storage mode:`,
          storageInfo.mode,
          `| Initialized:`,
          storageInfo.isInitialized,
        );

        if (!mounted) return false;

        setHasPassword(passwordAvailable);

        if (!passwordAvailable && !expiryMessage) {
          console.log(
            `[withPasswordProtection] No password found, redirecting to ${redirectTo}`,
          );
          navigate(redirectTo, {
            state: {
              from: location,
              message: customMessage,
            },
            replace: true,
          });
          return false;
        }

        return true;
      };

      // Initial check
      checkPasswordAsync().then((hasPass) => {
        if (!mounted) return;

        setIsChecking(false);

        // Set up periodic checking if specified and password exists
        if (checkInterval && hasPass) {
          intervalId = setInterval(() => {
            const stillHasPassword = passwordStorageService.hasPassword();
            if (!stillHasPassword && mounted && !expiryMessage) {
              console.log(
                "[withPasswordProtection] Password lost during periodic check, redirecting to session expired page...",
              );
              navigate(sessionExpiredRedirectTo, {
                state: {
                  from: location,
                  message: "Session expired",
                  reason: "periodic_check_timeout",
                },
                replace: true,
              });
            }
          }, checkInterval);
        }
      });

      return () => {
        mounted = false;
        window.removeEventListener("passwordExpired", handlePasswordExpired);
        if (intervalId) {
          clearInterval(intervalId);
        }
      };
    }, [
      navigate,
      location,
      redirectTo,
      sessionExpiredRedirectTo, // NEW: Include in dependencies
      checkInterval,
      customMessage,
      onPasswordExpired,
      expiryMessage,
      passwordStorageService,
      servicesAvailable,
    ]);

    // 🔧 NEW: Show loading while services initialize
    if (!servicesAvailable) {
      return (
        <div style={{ padding: "20px", textAlign: "center" }}>
          <p>Initializing services...</p>
          {import.meta.env.DEV && (
            <div style={{ fontSize: "12px", color: "#666", marginTop: "10px" }}>
              <p>
                Dev mode: Attempting to initialize password storage service...
              </p>
              <p>
                If this persists, check that ServiceProvider is properly
                configured
              </p>
            </div>
          )}
        </div>
      );
    }

    // Handle redirect when user clicks button on expiry modal
    const handleExpiryRedirect = () => {
      console.log(
        `[withPasswordProtection] User clicked redirect button, navigating to login`,
      );
      navigate(redirectTo, {
        state: {
          from: location,
          message: expiryMessage,
          reason: expiryReason,
        },
        replace: true,
      });
    };

    // Show expiry modal if password expired
    if (showExpiryModal) {
      return (
        <>
          {/* Backdrop */}
          <div
            style={{
              position: "fixed",
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              backgroundColor: "rgba(0, 0, 0, 0.5)",
              zIndex: 9998,
            }}
          />

          {/* Modal */}
          <div
            style={{
              position: "fixed",
              top: "50%",
              left: "50%",
              transform: "translate(-50%, -50%)",
              backgroundColor: "white",
              borderRadius: "8px",
              boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
              padding: "24px",
              maxWidth: "500px",
              width: "90%",
              zIndex: 9999,
            }}
          >
            <h2
              style={{
                margin: "0 0 16px 0",
                color: "#1f2937",
                fontSize: "24px",
              }}
            >
              ⚠️ Session Expired
            </h2>
            <p
              style={{
                margin: "0 0 24px 0",
                color: "#4b5563",
                lineHeight: "1.6",
              }}
            >
              {expiryMessage}
            </p>
            <p
              style={{
                margin: "0 0 24px 0",
                color: "#6b7280",
                fontSize: "14px",
              }}
            >
              Reason: <strong>{expiryReason}</strong>
            </p>
            <button
              onClick={handleExpiryRedirect}
              style={{
                width: "100%",
                padding: "12px 24px",
                backgroundColor: "#3b82f6",
                color: "white",
                border: "none",
                borderRadius: "6px",
                fontSize: "16px",
                fontWeight: "500",
                cursor: "pointer",
                transition: "background-color 0.2s",
              }}
              onMouseOver={(e) =>
                (e.currentTarget.style.backgroundColor = "#2563eb")
              }
              onMouseOut={(e) =>
                (e.currentTarget.style.backgroundColor = "#3b82f6")
              }
            >
              Return to Login
            </button>
          </div>
        </>
      );
    }

    // Show loading while checking
    if (isChecking && showLoadingWhileChecking) {
      return (
        <div style={{ padding: "20px", textAlign: "center" }}>
          <p>Checking authentication...</p>
          {import.meta.env.DEV && (
            <div style={{ fontSize: "12px", color: "#666", marginTop: "10px" }}>
              <p>
                Dev mode: Attempting to restore password from localStorage...
              </p>
              <p>
                Unified Services: Using window.mapleopentechServices for
                authManager access
              </p>
              <p>
                Token refresh: Automatic via ApiClient interceptors (no workers)
              </p>
              <p>
                Password timeout: Extended on user activity and API calls
                (logging reduced)
              </p>
              <p>Session expiry: Redirects to dedicated page for better UX</p>
            </div>
          )}
        </div>
      );
    }

    // If no password, don't render the component (redirect is happening)
    if (!hasPassword) {
      return (
        <div style={{ padding: "20px", textAlign: "center" }}>
          <p>{customMessage}</p>
        </div>
      );
    }

    // Render the protected component
    return <WrappedComponent {...props} />;
  };

  // Set display name for debugging
  PasswordProtectedComponent.displayName = `withPasswordProtection(${
    WrappedComponent.displayName || WrappedComponent.name
  })`;

  return PasswordProtectedComponent;
};

export default withPasswordProtection;

// ENHANCED: Additional debug helper with password service status
export const debugPasswordProtection = () => {
  // Import at runtime to avoid circular dependencies
  const { passwordStorageService } = window.mapleopentechServices || {};

  if (!passwordStorageService) {
    console.error("[withPasswordProtection] Password service not available");
    return null;
  }

  const info = passwordStorageService.getStorageInfo();

  console.log("Enhanced Password Protection Debug Info:");
  console.log("Service initialized:", passwordStorageService.isInitialized);
  console.log("Storage mode:", info.mode);
  console.log("Is development:", info.isDevelopment);
  console.log(
    "Has password in memory:",
    passwordStorageService.password !== null,
  );
  console.log("Unified Services available:", !!window.mapleopentechServices);
  console.log(
    "AuthManager available:",
    !!window.mapleopentechServices?.authManager,
  );
  console.log("Token refresh method: ApiClient interceptors (no workers)");
  console.log("Password timeout minutes:", info.timeoutMinutes);
  console.log("Activity detected:", info.activityDetected);
  console.log("Logging: Reduced verbosity for activity tracking");
  console.log(
    "Session expiry UX: Dedicated page with countdown and explanation",
  );
  console.log(
    "Storage type:",
    passwordStorageService.storage === localStorage
      ? "localStorage"
      : passwordStorageService.storage === sessionStorage
        ? "sessionStorage"
        : "unknown",
  );

  // Check localStorage directly
  const keys = Object.keys(localStorage).filter(
    (k) => k.includes("pwd") || k.includes("session"),
  );
  console.log("Password-related localStorage keys:", keys);

  return {
    serviceInfo: info,
    hasPasswordInMemory: passwordStorageService.password !== null,
    localStorageKeys: keys,
    refreshMethod: "api_interceptor",
    hasWorkers: false,
    timeoutMinutes: info.timeoutMinutes,
    activityDetected: info.activityDetected,
    loggingMode: "reduced_verbosity",
    sessionExpiryUX: "dedicated_page_with_countdown",
    unifiedServicesAvailable: !!window.mapleopentechServices,
    authManagerAvailable: !!window.mapleopentechServices?.authManager,
  };
};

// ENHANCED: Utility to manually extend password timeout
export const extendPasswordTimeout = () => {
  const { passwordStorageService } = window.mapleopentechServices || {};

  if (!passwordStorageService) {
    console.error("[withPasswordProtection] Password service not available");
    return false;
  }

  if (passwordStorageService.hasPassword()) {
    passwordStorageService.resetTimeout();
    console.log("[withPasswordProtection] Password timeout manually extended");
    return true;
  } else {
    console.warn(
      "[withPasswordProtection] No password available to extend timeout",
    );
    return false;
  }
};

// ENHANCED: Utility to get password service status
export const getPasswordServiceStatus = () => {
  const { passwordStorageService } = window.mapleopentechServices || {};

  if (!passwordStorageService) {
    console.error("[withPasswordProtection] Password service not available");
    return null;
  }

  return {
    hasPassword: passwordStorageService.hasPassword(),
    isInitialized: passwordStorageService.isInitialized,
    storageInfo: passwordStorageService.getStorageInfo(),
    detailedStatus: passwordStorageService.getDetailedStatus
      ? passwordStorageService.getDetailedStatus()
      : null,
    unifiedServicesIntegration: {
      available: !!window.mapleopentechServices,
      authManager: !!window.mapleopentechServices?.authManager,
      passwordStorageService:
        !!window.mapleopentechServices?.passwordStorageService,
    },
    sessionExpiryFeatures: {
      dedicatedPage: true,
      autoRedirectCountdown: true,
      reasonBasedMessages: true,
      securityExplanation: true,
    },
  };
};
