import React, { createContext, useContext, useState, useEffect, useCallback, useRef, ReactNode } from 'react';
import { useADHDMode } from './ADHDModeProvider';
import { useMutation, useQueryClient } from '@tanstack/react-query';

interface BreakReminderContextType {
  isReminderVisible: boolean;
  minutesSinceBreak: number;
  logBreak: (breakType: string, durationMinutes?: number) => void;
  snooze: (minutes: number) => void;
  dismiss: () => void;
  lastBreakAt: Date | null;
}

const BreakReminderContext = createContext<BreakReminderContextType | undefined>(undefined);

export function BreakReminderProvider({ children }: { children: ReactNode }) {
  const { isEnabled, settings } = useADHDMode();
  const queryClient = useQueryClient();

  const [isReminderVisible, setIsReminderVisible] = useState(false);
  const [minutesSinceBreak, setMinutesSinceBreak] = useState(0);
  const [lastBreakAt, setLastBreakAt] = useState<Date | null>(null);
  const [snoozeUntil, setSnoozeUntil] = useState<Date | null>(null);

  // Track accumulated active minutes instead of time since break
  const accumulatedMinutesRef = useRef(0);
  const lastTickRef = useRef<number>(Date.now());
  const isPageVisibleRef = useRef(true);

  // Reset accumulated minutes when break is taken or on page load
  useEffect(() => {
    const stored = localStorage.getItem('accumulatedActiveMinutes');
    const storedTime = localStorage.getItem('lastActiveTime');

    if (stored && storedTime) {
      // Only restore if less than 8 hours have passed (assume they took a real break)
      const lastActive = new Date(storedTime).getTime();
      const hoursSinceActive = (Date.now() - lastActive) / (1000 * 60 * 60);

      if (hoursSinceActive < 8) {
        accumulatedMinutesRef.current = parseInt(stored, 10) || 0;
      } else {
        // Reset after long break
        accumulatedMinutesRef.current = 0;
        localStorage.setItem('accumulatedActiveMinutes', '0');
      }
    }

    // Legacy: load lastBreakAt for backward compatibility
    const storedBreak = localStorage.getItem('lastBreakAt');
    if (storedBreak) {
      setLastBreakAt(new Date(storedBreak));
    } else {
      const now = new Date();
      setLastBreakAt(now);
      localStorage.setItem('lastBreakAt', now.toISOString());
    }

    setMinutesSinceBreak(accumulatedMinutesRef.current);
  }, []);

  // Track page visibility
  useEffect(() => {
    const handleVisibilityChange = () => {
      const isVisible = document.visibilityState === 'visible';

      if (!isVisible && isPageVisibleRef.current) {
        // Page becoming hidden - save current state
        localStorage.setItem('accumulatedActiveMinutes', String(accumulatedMinutesRef.current));
        localStorage.setItem('lastActiveTime', new Date().toISOString());
      } else if (isVisible && !isPageVisibleRef.current) {
        // Page becoming visible - update last tick to now to avoid counting hidden time
        lastTickRef.current = Date.now();
      }

      isPageVisibleRef.current = isVisible;
    };

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

  // Log break mutation
  const logBreakMutation = useMutation({
    mutationFn: async ({ breakType, durationMinutes }: { breakType: string; durationMinutes: number }) => {
      const res = await fetch('/api/user/log-break', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ breakType, durationMinutes }),
      });
      if (!res.ok) throw new Error('Failed to log break');
      return res.json();
    },
  });

  const logBreak = useCallback((breakType: string, durationMinutes = 5) => {
    const now = new Date();
    setLastBreakAt(now);
    localStorage.setItem('lastBreakAt', now.toISOString());
    setIsReminderVisible(false);
    setSnoozeUntil(null);

    // Reset accumulated time
    accumulatedMinutesRef.current = 0;
    setMinutesSinceBreak(0);
    localStorage.setItem('accumulatedActiveMinutes', '0');
    localStorage.setItem('lastActiveTime', now.toISOString());
    lastTickRef.current = Date.now();

    // Log to server
    logBreakMutation.mutate({ breakType, durationMinutes });
  }, [logBreakMutation]);

  const snooze = useCallback((minutes: number) => {
    const snoozeTime = new Date(Date.now() + minutes * 60 * 1000);
    setSnoozeUntil(snoozeTime);
    setIsReminderVisible(false);
  }, []);

  const dismiss = useCallback(() => {
    setIsReminderVisible(false);
  }, []);

  // Timer to track ACTIVE minutes since break (only when page is visible)
  useEffect(() => {
    if (!isEnabled) return;

    const interval = setInterval(() => {
      const now = Date.now();

      // Only count time if page is visible
      if (isPageVisibleRef.current) {
        const elapsedMs = now - lastTickRef.current;
        const elapsedMins = elapsedMs / 60000;

        // Add to accumulated time
        accumulatedMinutesRef.current += elapsedMins;
        setMinutesSinceBreak(Math.floor(accumulatedMinutesRef.current));

        // Save periodically
        localStorage.setItem('accumulatedActiveMinutes', String(Math.floor(accumulatedMinutesRef.current)));
        localStorage.setItem('lastActiveTime', new Date().toISOString());
      }

      lastTickRef.current = now;

      // Check if reminder should be shown
      const reminderInterval = settings.breakReminderInterval || 45;

      // Check snooze
      if (snoozeUntil && new Date() < snoozeUntil) {
        return;
      }

      if (accumulatedMinutesRef.current >= reminderInterval && !isReminderVisible) {
        setIsReminderVisible(true);
        setSnoozeUntil(null);
      }
    }, 30000); // Check every 30 seconds

    return () => clearInterval(interval);
  }, [isEnabled, settings.breakReminderInterval, snoozeUntil, isReminderVisible]);

  return (
    <BreakReminderContext.Provider
      value={{
        isReminderVisible,
        minutesSinceBreak,
        logBreak,
        snooze,
        dismiss,
        lastBreakAt,
      }}
    >
      {children}
    </BreakReminderContext.Provider>
  );
}

export function useBreakReminder() {
  const context = useContext(BreakReminderContext);
  if (context === undefined) {
    throw new Error('useBreakReminder must be used within a BreakReminderProvider');
  }
  return context;
}
