import { useState, useEffect, useCallback, useRef } from 'react';
import { Layout, Layouts } from 'react-grid-layout';
import axios from 'axios';
import {
  DashboardLayout,
  WidgetSettings,
  DEFAULT_LAYOUTS,
  DEFAULT_WIDGET_SETTINGS,
} from '../types/dashboard';

interface UseDashboardLayoutReturn {
  layouts: Layouts;
  widgetSettings: WidgetSettings;
  loading: boolean;
  saving: boolean;
  error: string | null;

  // Layout actions
  updateLayouts: (newLayouts: Layouts) => void;
  resetLayouts: () => void;
  saveLayouts: () => Promise<void>;

  // Widget settings actions
  updateWidgetSettings: <K extends keyof WidgetSettings>(
    widget: K,
    settings: Partial<WidgetSettings[K]>
  ) => void;
  updatePipSettings: (settings: Partial<WidgetSettings['pip']>) => void;
  updateVisibility: (widgetId: string, visible: boolean) => void;
}

const STORAGE_KEY = 'zeiterfassung_dashboard_layout';

/**
 * Merge saved layouts with defaults to ensure new widgets are included.
 * Existing widget positions are preserved; missing widgets get appended from defaults.
 */
/**
 * Merge saved widget settings with defaults to ensure new keys are included.
 */
function mergeWidgetSettings(saved: Partial<WidgetSettings>): WidgetSettings {
  return {
    ...DEFAULT_WIDGET_SETTINGS,
    ...saved,
    visibility: {
      ...DEFAULT_WIDGET_SETTINGS.visibility,
      ...(saved.visibility || {}),
    },
    pip: {
      ...DEFAULT_WIDGET_SETTINGS.pip,
      ...(saved.pip || {}),
    },
  };
}

function mergeLayoutsWithDefaults(saved: Layouts): Layouts {
  const merged: Layouts = {};
  for (const breakpoint of Object.keys(DEFAULT_LAYOUTS)) {
    const defaultItems = DEFAULT_LAYOUTS[breakpoint];
    const savedItems = saved[breakpoint] || [];
    const savedKeys = new Set(savedItems.map((item: Layout) => item.i));

    const missing = defaultItems.filter((item: Layout) => !savedKeys.has(item.i));
    merged[breakpoint] = [...savedItems, ...missing];
  }
  return merged;
}

export function useDashboardLayout(): UseDashboardLayoutReturn {
  const [layouts, setLayouts] = useState<Layouts>(DEFAULT_LAYOUTS);
  const [widgetSettings, setWidgetSettings] = useState<WidgetSettings>(DEFAULT_WIDGET_SETTINGS);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const serverSaveTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  // Load layout from server or localStorage
  const loadLayout = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);

      // Try server first
      try {
        const response = await axios.get('/zeiterfassung/dashboard/layout');
        if (response.data && response.data.layoutJson) {
          const parsed = JSON.parse(response.data.layoutJson);
          setLayouts(mergeLayoutsWithDefaults(parsed.layouts || DEFAULT_LAYOUTS));
          setWidgetSettings(mergeWidgetSettings(response.data.widgetSettings || {}));
          return;
        }
      } catch (serverError) {
        // Server doesn't have layout, try localStorage
        console.log('No server layout, checking localStorage');
      }

      // Fallback to localStorage
      const stored = localStorage.getItem(STORAGE_KEY);
      if (stored) {
        const parsed = JSON.parse(stored);
        setLayouts(parsed.layouts || DEFAULT_LAYOUTS);
        setWidgetSettings(mergeWidgetSettings(parsed.widgetSettings || {}));
      }
    } catch (err: any) {
      console.error('Error loading dashboard layout:', err);
      setError('Failed to load layout');
      // Use defaults on error
      setLayouts(DEFAULT_LAYOUTS);
      setWidgetSettings(DEFAULT_WIDGET_SETTINGS);
    } finally {
      setLoading(false);
    }
  }, []);

  // Debounced server save to prevent race conditions
  const scheduleServerSave = useCallback((layoutData: DashboardLayout) => {
    // Clear any pending server save
    if (serverSaveTimeoutRef.current) {
      clearTimeout(serverSaveTimeoutRef.current);
    }

    serverSaveTimeoutRef.current = setTimeout(async () => {
      try {
        setSaving(true);
        setError(null);
        await axios.put('/zeiterfassung/dashboard/layout', {
          layout_json: JSON.stringify({ layouts: layoutData.layouts }),
          widget_settings: layoutData.widgetSettings,
        });
      } catch (err: any) {
        console.error('Error saving dashboard layout:', err);
        setError('Failed to save layout');
      } finally {
        setSaving(false);
      }
    }, 1000); // Debounce server saves by 1 second
  }, []);

  // Save layout to server and localStorage
  const saveLayouts = useCallback(async () => {
    const data: DashboardLayout = {
      layouts,
      widgetSettings,
    };

    // Save to localStorage immediately
    localStorage.setItem(STORAGE_KEY, JSON.stringify(data));

    // Schedule debounced server save
    scheduleServerSave(data);
  }, [layouts, widgetSettings, scheduleServerSave]);

  // Update layouts (called on drag/resize)
  const updateLayouts = useCallback((newLayouts: Layouts) => {
    setLayouts(newLayouts);
    // Debounced save happens in useEffect
  }, []);

  // Reset to default layouts
  const resetLayouts = useCallback(() => {
    setLayouts(DEFAULT_LAYOUTS);
    setWidgetSettings(DEFAULT_WIDGET_SETTINGS);
    localStorage.removeItem(STORAGE_KEY);
  }, []);

  // Update specific widget settings
  const updateWidgetSettings = useCallback(<K extends keyof WidgetSettings>(
    widget: K,
    settings: Partial<WidgetSettings[K]>
  ) => {
    setWidgetSettings((prev) => ({
      ...prev,
      [widget]: {
        ...prev[widget],
        ...settings,
      },
    }));
  }, []);

  // Toggle widget visibility
  const updateVisibility = useCallback((widgetId: string, visible: boolean) => {
    setWidgetSettings((prev) => ({
      ...prev,
      visibility: {
        ...prev.visibility,
        [widgetId]: visible,
      },
    }));
  }, []);

  // Convenience method for PiP settings
  const updatePipSettings = useCallback((settings: Partial<WidgetSettings['pip']>) => {
    updateWidgetSettings('pip', settings);

    // Dispatch custom event when globalPipEnabled changes
    // This notifies the Global PIP component in the same tab
    if (settings.globalPipEnabled !== undefined) {
      window.dispatchEvent(new CustomEvent('globalPipSettingChanged'));
    }
  }, [updateWidgetSettings]);

  // Load on mount
  useEffect(() => {
    loadLayout();
  }, [loadLayout]);

  // Auto-save on layout change (debounced)
  useEffect(() => {
    if (loading) return;

    const timeout = setTimeout(() => {
      const data: DashboardLayout = { layouts, widgetSettings };
      // Save to localStorage
      localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
      // Schedule unified server save
      scheduleServerSave(data);
    }, 500);

    return () => clearTimeout(timeout);
  }, [layouts, widgetSettings, loading, scheduleServerSave]);

  // Cleanup server save timeout on unmount
  useEffect(() => {
    return () => {
      if (serverSaveTimeoutRef.current) {
        clearTimeout(serverSaveTimeoutRef.current);
      }
    };
  }, []);

  return {
    layouts,
    widgetSettings,
    loading,
    saving,
    error,
    updateLayouts,
    resetLayouts,
    saveLayouts,
    updateWidgetSettings,
    updatePipSettings,
    updateVisibility,
  };
}

export default useDashboardLayout;
