import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import api from '../utils/api';
import logger from '../utils/logger';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from './ui/dialog';
import { Button } from './ui/button';
import { AlertTriangle, RefreshCw } from 'lucide-react';

/**
 * IdleSessionWarning Component
 *
 * Monitors user activity and warns before session expiration
 * - Warns 1 minute before JWT expiry (at 29 minutes if JWT is 30 min)
 * - Auto-logout on expiration
 * - "Stay Logged In" extends session
 * - Checks session validity when tab becomes visible after being hidden
 */
const IdleSessionWarning = () => {
  const { user, logout, refreshUser } = useAuth();
  const navigate = useNavigate();

  // Configuration
  const SESSION_DURATION = 30 * 60 * 1000; // 30 minutes in milliseconds
  const WARNING_BEFORE_EXPIRY = 1 * 60 * 1000; // Warn 1 minute before expiry
  const WARNING_TIME = SESSION_DURATION - WARNING_BEFORE_EXPIRY; // 29 minutes

  const [showWarning, setShowWarning] = useState(false);
  const [timeRemaining, setTimeRemaining] = useState(60); // seconds
  const [isExtending, setIsExtending] = useState(false);
  const [isCheckingSession, setIsCheckingSession] = useState(false);

  const activityTimeoutRef = useRef(null);
  const warningTimeoutRef = useRef(null);
  const countdownIntervalRef = useRef(null);
  const lastActivityRef = useRef(Date.now());
  const lastVisibilityCheckRef = useRef(Date.now());

  // Reset activity timer
  const resetActivityTimer = useCallback(() => {
    lastActivityRef.current = Date.now();

    // Clear existing timers
    if (activityTimeoutRef.current) {
      clearTimeout(activityTimeoutRef.current);
    }
    if (warningTimeoutRef.current) {
      clearTimeout(warningTimeoutRef.current);
    }
    if (countdownIntervalRef.current) {
      clearInterval(countdownIntervalRef.current);
    }

    // Hide warning if showing
    if (showWarning) {
      setShowWarning(false);
    }

    // Set new warning timer
    warningTimeoutRef.current = setTimeout(() => {
      // Show warning
      setShowWarning(true);
      setTimeRemaining(60); // 60 seconds until logout

      // Start countdown
      countdownIntervalRef.current = setInterval(() => {
        setTimeRemaining((prev) => {
          if (prev <= 1) {
            // Time's up - logout
            handleSessionExpired();
            return 0;
          }
          return prev - 1;
        });
      }, 1000);

      // Set auto-logout timer
      activityTimeoutRef.current = setTimeout(() => {
        handleSessionExpired();
      }, WARNING_BEFORE_EXPIRY);

    }, WARNING_TIME);
  }, [showWarning]);

  // Handle session expiration
  const handleSessionExpired = useCallback(() => {
    // Clear all timers
    if (activityTimeoutRef.current) clearTimeout(activityTimeoutRef.current);
    if (warningTimeoutRef.current) clearTimeout(warningTimeoutRef.current);
    if (countdownIntervalRef.current) clearInterval(countdownIntervalRef.current);

    setShowWarning(false);
    logout();
    navigate('/login', {
      state: { message: 'Your session has expired due to inactivity. Please log in again.' }
    });
  }, [logout, navigate]);

  // Handle "Stay Logged In" button
  const handleExtendSession = async () => {
    setIsExtending(true);
    try {
      // Refresh user data to get new token
      await refreshUser();

      // Reset activity timer
      resetActivityTimer();

      logger.log('[IdleSessionWarning] Session extended successfully');
    } catch (error) {
      logger.error('[IdleSessionWarning] Failed to extend session:', error);

      // If refresh fails, logout
      handleSessionExpired();
    } finally {
      setIsExtending(false);
    }
  };

  // Check if session is still valid (called when tab becomes visible)
  const checkSessionValidity = useCallback(async () => {
    if (!user || isCheckingSession) return;

    const token = localStorage.getItem('token');
    if (!token) {
      logger.log('[IdleSessionWarning] No token found on visibility change');
      handleSessionExpired();
      return;
    }

    setIsCheckingSession(true);
    try {
      // Make a lightweight API call to verify token is still valid
      await api.get('/auth/me');
      logger.log('[IdleSessionWarning] Session still valid after visibility change');

      // Reset the activity timer since user is back
      resetActivityTimer();
    } catch (error) {
      logger.error('[IdleSessionWarning] Session invalid on visibility change:', error);

      // If 401, the interceptor will handle redirect
      // For other errors, still redirect to be safe
      if (error.response?.status !== 401) {
        handleSessionExpired();
      }
    } finally {
      setIsCheckingSession(false);
    }
  }, [user, isCheckingSession, handleSessionExpired, resetActivityTimer]);

  // Handle visibility change (when user returns to tab after being away)
  useEffect(() => {
    if (!user) return;

    const handleVisibilityChange = () => {
      if (document.visibilityState === 'visible') {
        const now = Date.now();
        const timeSinceLastCheck = now - lastVisibilityCheckRef.current;

        // Only check if tab was hidden for more than 1 minute
        // This prevents unnecessary API calls for quick tab switches
        if (timeSinceLastCheck > 60 * 1000) {
          logger.log('[IdleSessionWarning] Tab became visible after', Math.round(timeSinceLastCheck / 1000), 'seconds');
          checkSessionValidity();
        }

        lastVisibilityCheckRef.current = now;
      }
    };

    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [user, checkSessionValidity]);

  // Listen for session expired event from API interceptor
  useEffect(() => {
    const handleAuthSessionExpired = () => {
      logger.log('[IdleSessionWarning] Received auth:session-expired event');
      // Clear all timers
      if (activityTimeoutRef.current) clearTimeout(activityTimeoutRef.current);
      if (warningTimeoutRef.current) clearTimeout(warningTimeoutRef.current);
      if (countdownIntervalRef.current) clearInterval(countdownIntervalRef.current);
      setShowWarning(false);
    };

    window.addEventListener('auth:session-expired', handleAuthSessionExpired);

    return () => {
      window.removeEventListener('auth:session-expired', handleAuthSessionExpired);
    };
  }, []);

  // Track user activity
  useEffect(() => {
    if (!user) return;

    const activityEvents = [
      'mousedown',
      'mousemove',
      'keypress',
      'scroll',
      'touchstart',
      'click'
    ];

    // Throttle activity detection to avoid too many resets
    let throttleTimeout = null;
    const handleActivity = () => {
      if (throttleTimeout) return;

      throttleTimeout = setTimeout(() => {
        resetActivityTimer();
        throttleTimeout = null;
      }, 1000); // Throttle to once per second
    };

    // Add event listeners
    activityEvents.forEach(event => {
      document.addEventListener(event, handleActivity, { passive: true });
    });

    // Initialize timer
    resetActivityTimer();

    // Cleanup
    return () => {
      activityEvents.forEach(event => {
        document.removeEventListener(event, handleActivity);
      });

      if (activityTimeoutRef.current) clearTimeout(activityTimeoutRef.current);
      if (warningTimeoutRef.current) clearTimeout(warningTimeoutRef.current);
      if (countdownIntervalRef.current) clearInterval(countdownIntervalRef.current);
      if (throttleTimeout) clearTimeout(throttleTimeout);
    };
  }, [user, resetActivityTimer]);

  // Don't render if user is not logged in
  if (!user) return null;

  return (
    <Dialog open={showWarning} onOpenChange={(open) => {
      if (!open) {
        // Prevent closing dialog by clicking outside
        // User must click a button
        return;
      }
    }}>
      <DialogContent
        className="max-w-md"
        onPointerDownOutside={(e) => e.preventDefault()}
        onEscapeKeyDown={(e) => e.preventDefault()}
      >
        <DialogHeader>
          <div className="flex items-center gap-3 mb-2">
            <div className="bg-[#ff9e77]/10 p-3 rounded-full">
              <AlertTriangle className="h-6 w-6 text-[#ff9e77]" />
            </div>
            <DialogTitle className="text-[#422268]">
              Session About to Expire
            </DialogTitle>
          </div>
          <DialogDescription className="text-[#664fa3]">
            Your session will expire in <strong className="text-[#422268] text-lg">{timeRemaining}</strong> seconds due to inactivity.

            <div className="mt-4 p-4 bg-[#f1eef9] rounded-lg border border-[#ddd8eb]">
              <p className="text-sm text-[#422268]">
                Click <strong>"Stay Logged In"</strong> to continue your session, or you will be automatically logged out.
              </p>
            </div>
          </DialogDescription>
        </DialogHeader>

        <DialogFooter className="flex-col sm:flex-row gap-3 mt-4">
          <Button
            variant="outline"
            onClick={handleSessionExpired}
            className="border-[#ddd8eb] text-[#664fa3] hover:bg-[#f1eef9]"
          >
            Log Out Now
          </Button>
          <Button
            onClick={handleExtendSession}
            disabled={isExtending}
            className="bg-[#664fa3] hover:bg-[#422268] text-white"
          >
            {isExtending ? (
              <>
                <RefreshCw className="h-4 w-4 mr-2 animate-spin" />
                Extending...
              </>
            ) : (
              'Stay Logged In'
            )}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};

export default IdleSessionWarning;
