/**
 * useInAppContent - Custom hook for managing device-specific content in InApp variant
 *
 * Manages separate HTML content for Android and iOS devices with sync functionality
 */

import {
  useState, useCallback, useRef, useEffect, useMemo,
} from 'react';
import { DEVICE_TYPES, PERFORMANCE } from '../constants';

// Constants for better maintainability
const CONTENT_VALIDATION = {
  MIN_CONTENT_LENGTH: 0,
  DEFAULT_CONTENT_TYPE: 'string',
};

const AUTO_SAVE_CONFIG = {
  DEFAULT_ENABLED: true,
  DEFAULT_INTERVAL: PERFORMANCE.AUTO_SAVE_INTERVAL,
  MIN_AUTO_SAVE_INTERVAL_MS: 1000, // Minimum 1 second between auto-saves
};

/**
 * Default InApp content for different devices
 * Empty strings - no default content for new templates
 */
const DEFAULT_INAPP_CONTENT = {
  [DEVICE_TYPES.ANDROID]: '',
  [DEVICE_TYPES.IOS]: '',
};

/**
 * Custom hook for InApp content management with device-specific content
 *
 * @param {Object} initialContent - Initial content for both devices
 * @param {Object} options - Configuration options
 * @param {boolean} options.autoSave - Enable auto-save functionality
 * @param {number} options.autoSaveInterval - Auto-save interval in milliseconds
 * @param {Function} options.onSave - Callback when content is saved
 * @param {Function} options.onChange - Callback when content changes
 * @returns {Object} Content state and methods
 */
export const useInAppContent = (initialContent = {}, options = {}) => {
  // Destructure options with better defaults
  const {
    autoSave = AUTO_SAVE_CONFIG.DEFAULT_ENABLED,
    autoSaveInterval = AUTO_SAVE_CONFIG.DEFAULT_INTERVAL,
    onSave,
    onChange,
  } = options;

  // Destructure device types for cleaner code
  const { ANDROID, IOS } = DEVICE_TYPES;

  // Device-specific content state with optional chaining
  const [deviceContent, setDeviceContent] = useState(() => ({
    [ANDROID]: initialContent?.[ANDROID] || DEFAULT_INAPP_CONTENT[ANDROID],
    [IOS]: initialContent?.[IOS] || DEFAULT_INAPP_CONTENT[IOS],
  }));

  // Current active device
  const [activeDevice, setActiveDevice] = useState(ANDROID);

  // Content sync state
  const [keepContentSame, setKeepContentSame] = useState(false);

  // Dirty state tracking
  const [isDirty, setIsDirty] = useState(false);
  const [lastSaved, setLastSaved] = useState(null);

  // Auto-save timer
  const autoSaveTimerRef = useRef(null);
  const changeTimestampRef = useRef(null);

  // Refs to store current values for auto-save
  const onSaveRef = useRef(onSave);
  const deviceContentRef = useRef(deviceContent);

  // Update refs when values change
  useEffect(() => {
    onSaveRef.current = onSave;
  }, [onSave]);

  useEffect(() => {
    deviceContentRef.current = deviceContent;
  }, [deviceContent]);

  // Ref to track if we've loaded initial content to prevent overriding user edits
  const initialContentLoadedRef = useRef(false);
  const previousContentRef = useRef({ android: '', ios: '' });

  // Update content when initialContent prop changes (for edit mode)
  // This should only run when loading a template for editing, NOT during active editing
  useEffect(() => {
    const newAndroidContent = initialContent?.[ANDROID];
    const newIosContent = initialContent?.[IOS];

    // Check if this is meaningful initialContent (has actual content)
    const hasMeaningfulContent = (newAndroidContent && newAndroidContent.trim() !== '')
      || (newIosContent && newIosContent.trim() !== '');

    // Check if we're transitioning from empty to meaningful content (library mode scenario)
    const wasEmpty = (!previousContentRef.current.android || previousContentRef.current.android.trim() === '')
      && (!previousContentRef.current.ios || previousContentRef.current.ios.trim() === '');
    const isTransitioningToContent = wasEmpty && hasMeaningfulContent;

    // Only update if:
    // 1. We haven't loaded initial content yet (first load), OR
    // 2. We're transitioning from empty to meaningful content (library mode data fetch)
    // This prevents the effect from overriding user edits during active editing
    // while still allowing content to load properly in library mode
    if (!initialContentLoadedRef.current || isTransitioningToContent) {
      if (hasMeaningfulContent) {
        // Mark as loaded to prevent future updates from overriding user edits
        initialContentLoadedRef.current = true;

        setDeviceContent((prev) => {
          let updated = false;
          const updatedContent = { ...prev };

          if (newAndroidContent !== undefined && newAndroidContent !== prev[ANDROID]) {
            updatedContent[ANDROID] = newAndroidContent;
            updated = true;
          }
          if (newIosContent !== undefined && newIosContent !== prev[IOS]) {
            updatedContent[IOS] = newIosContent;
            updated = true;
          }

          return updated ? updatedContent : prev;
        });

        // Update previous content ref
        previousContentRef.current = {
          android: newAndroidContent || '',
          ios: newIosContent || '',
        };
      }
    }
  }, [initialContent, ANDROID, IOS]);

  // Get current active content
  const currentContent = useMemo(() => deviceContent?.[activeDevice] || '', [deviceContent, activeDevice]);

  // Update content for current device
  const updateContent = useCallback((newContent) => {
    // Validate input
    if (typeof newContent !== CONTENT_VALIDATION?.DEFAULT_CONTENT_TYPE) {
      console.warn('useInAppContent: newContent must be a string');
      return;
    }

    // Create the updated content object
    let updatedDeviceContent;

    if (keepContentSame) {
      // When sync is enabled, update both devices with the same content
      updatedDeviceContent = {
        [ANDROID]: newContent,
        [IOS]: newContent,
      };
    } else {
      // When sync is disabled, update only the current device
      setDeviceContent((prev) => {
        updatedDeviceContent = {
          ...prev,
          [activeDevice]: newContent,
        };
        return updatedDeviceContent;
      });

      // Early return for independent mode to avoid double state update
      setIsDirty(true);
      changeTimestampRef.current = Date.now();

      // Trigger onChange callback - pass only changed device content
      // This prevents parent from updating both device states when only one changed
      onChange?.({ [activeDevice]: newContent }, activeDevice);

      // Setup auto-save for independent mode
      if (autoSave && autoSaveInterval > AUTO_SAVE_CONFIG.MIN_AUTO_SAVE_INTERVAL_MS && newContent.length > CONTENT_VALIDATION.MIN_CONTENT_LENGTH) {
        if (autoSaveTimerRef.current) {
          clearTimeout(autoSaveTimerRef.current);
        }
        autoSaveTimerRef.current = setTimeout(() => {
          // Use current values at time of execution
          setIsDirty(false);
          setLastSaved(new Date());

          if (autoSaveTimerRef.current) {
            clearTimeout(autoSaveTimerRef.current);
            autoSaveTimerRef.current = null;
          }

          // Get the current onSave callback and deviceContent from refs
          const currentOnSave = onSaveRef.current;
          currentOnSave?.(deviceContentRef.current);
        }, autoSaveInterval);
      }

      return;
    }

    // Handle sync mode state update
    setDeviceContent(updatedDeviceContent);
    setIsDirty(true);
    changeTimestampRef.current = Date.now();

    // Trigger onChange callback - in sync mode, pass full content
    onChange?.(updatedDeviceContent, activeDevice);

    // Setup auto-save
    if (autoSave && autoSaveInterval > AUTO_SAVE_CONFIG.MIN_AUTO_SAVE_INTERVAL_MS && newContent.length > CONTENT_VALIDATION.MIN_CONTENT_LENGTH) {
      if (autoSaveTimerRef.current) {
        clearTimeout(autoSaveTimerRef.current);
      }
      autoSaveTimerRef.current = setTimeout(() => {
        // Use current values at time of execution
        setIsDirty(false);
        setLastSaved(new Date());

        if (autoSaveTimerRef.current) {
          clearTimeout(autoSaveTimerRef.current);
          autoSaveTimerRef.current = null;
        }

        // Get the current onSave callback and deviceContent from refs
        const currentOnSave = onSaveRef.current;
        currentOnSave?.(deviceContentRef.current);
      }, autoSaveInterval);
    }
  }, [activeDevice, keepContentSame, autoSave, autoSaveInterval, onChange]);

  // Switch active device with better validation
  const switchDevice = useCallback((device) => {
    const validDevices = [ANDROID, IOS];
    if (device !== activeDevice && validDevices.includes(device)) {
      setActiveDevice(device);
    } else if (!validDevices.includes(device)) {
      console.warn(`useInAppContent: Invalid device type "${device}". Valid types are: ${validDevices.join(', ')}`);
    }
  }, [activeDevice, ANDROID, IOS]);

  // Toggle content sync
  const toggleContentSync = useCallback((enabled) => {
    setKeepContentSame(enabled);

    if (enabled) {
      // When enabling sync, copy current device content to the other device
      const currentActiveContent = deviceContent[activeDevice];
      const syncedContent = {
        [ANDROID]: currentActiveContent,
        [IOS]: currentActiveContent,
      };

      setDeviceContent(syncedContent);
      setIsDirty(true);
    }
    // When disabled (enabled = false), we don't need to do anything special
    // Each device will maintain its current content independently
  }, [activeDevice, deviceContent]);

  // Mark content as saved
  const markAsSaved = useCallback(() => {
    setIsDirty(false);
    setLastSaved(new Date());

    if (autoSaveTimerRef.current) {
      clearTimeout(autoSaveTimerRef.current);
      autoSaveTimerRef.current = null;
    }

    onSave?.(deviceContent);
  }, [deviceContent, onSave]);

  // Check if content exists for current device
  const hasContent = useMemo(() => typeof currentContent === CONTENT_VALIDATION.DEFAULT_CONTENT_TYPE
    && currentContent?.trim()?.length > CONTENT_VALIDATION.MIN_CONTENT_LENGTH, [currentContent]);

  // Get content size for current device
  const getContentSize = useCallback(() => typeof currentContent === CONTENT_VALIDATION.DEFAULT_CONTENT_TYPE
    ? currentContent?.length
    : CONTENT_VALIDATION?.MIN_CONTENT_LENGTH, [currentContent]);

  // Get content for specific device
  const getDeviceContent = useCallback((device) => deviceContent[device] || '', [deviceContent]);

  // Set content for specific device
  const setDeviceContent_ = useCallback((device, content) => {
    const validDevices = [ANDROID, IOS];

    if (!validDevices.includes(device)) {
      console.warn(`useInAppContent: Invalid device type "${device}". Valid types are: ${validDevices.join(', ')}`);
      return;
    }

    if (typeof content !== CONTENT_VALIDATION.DEFAULT_CONTENT_TYPE) {
      console.warn('useInAppContent: content must be a string');
      return;
    }

    if (keepContentSame) {
      // Update both devices when sync is enabled
      setDeviceContent({
        [ANDROID]: content,
        [IOS]: content,
      });
    } else {
      // Update specific device
      setDeviceContent((prev) => ({
        ...prev,
        [device]: content,
      }));
    }
    setIsDirty(true);
  }, [keepContentSame, ANDROID, IOS]);

  // Cleanup on unmount
  useEffect(() => () => {
    if (autoSaveTimerRef.current) {
      clearTimeout(autoSaveTimerRef.current);
    }
  }, []);

  return {
    // Current state
    content: currentContent,
    deviceContent,
    activeDevice,
    keepContentSame,
    isDirty,
    lastSaved,
    hasContent,

    // Content management
    updateContent,
    getDeviceContent,
    setDeviceContent: setDeviceContent_,
    getContentSize,

    // Device management
    switchDevice,
    toggleContentSync,

    // Save management
    markAsSaved,
  };
};
