/**
 * Shell
 * Provides shell state management, context, provider, placement, and singleton manager
 * Platform-agnostic shell system for UI layout control
 */

import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import { XStack, YStack, Text, Button, Spinner } from 'tamagui';
import RecordsModel from '../../data/RecordsModel.js';
import { getIcon } from './IconMapper.jsx';
import { SidePanelShell } from './SidePanelShell.jsx';
import { networkActivityManager } from '../../platform/api.js';

// ============================================================================
// Shell Context
// ============================================================================

const ShellContext = createContext(null);

// ============================================================================
// Shell Manager (Singleton)
// ============================================================================

/**
 * Shell Manager
 * Singleton that maintains shell state and provides global access for handlers
 * Accessible via Shell.Manager for global access
 */
class ShellManager {
  constructor() {
    this._state = {
      leftSideWidth: 0,
      rightSideWidth: 0,
      headerHeight: 0,
      footerHeight: 0
    };
    this._setters = {
      setLeftSideWidth: null,
      setRightSideWidth: null,
      setHeaderHeight: null,
      setFooterHeight: null
    };
    this._listeners = new Set();
  }

  /**
   * Initialize shell manager (called by ShellProvider)
   * @param {Object} setters - State setter functions from ShellProvider
   */
  _init(setters) {
    this._setters = setters;
  }

  /**
   * Update internal state (called by ShellProvider)
   */
  _updateState(state) {
    this._state = { ...state };
    this._notifyListeners();
  }

  /**
   * Notify all listeners of state changes
   */
  _notifyListeners() {
    this._listeners.forEach(listener => {
      try {
        listener({ ...this._state });
      } catch (error) {
        console.warn('[ShellManager] Listener error:', error);
      }
    });
  }

  /**
   * Get current state
   * @returns {Object} Current shell state
   */
  getState() {
    return { ...this._state };
  }

  /**
   * Get left side width
   * @returns {number}
   */
  getLeftSideWidth() {
    return this._state.leftSideWidth;
  }

  /**
   * Get right side width
   * @returns {number}
   */
  getRightSideWidth() {
    return this._state.rightSideWidth;
  }

  /**
   * Set left side width
   * @param {number} width
   */
  setLeftSideWidth(width) {
    if (this._setters.setLeftSideWidth) {
      this._setters.setLeftSideWidth(width);
    } else {
      console.warn('[ShellManager] setLeftSideWidth not initialized');
    }
  }

  /**
   * Set right side width
   * @param {number} width
   */
  setRightSideWidth(width) {
    if (this._setters.setRightSideWidth) {
      this._setters.setRightSideWidth(width);
    } else {
      console.warn('[ShellManager] setRightSideWidth not initialized');
    }
  }

  /**
   * Toggle left side
   * @param {number} [targetWidth=250] - Target width when opening
   */
  toggleLeftSide(targetWidth = 250) {
    const currentWidth = this._state.leftSideWidth;
    this.setLeftSideWidth(currentWidth === 0 ? targetWidth : 0);
  }

  /**
   * Toggle right side
   * @param {number} [targetWidth=250] - Target width when opening
   */
  toggleRightSide(targetWidth = 250) {
    const currentWidth = this._state.rightSideWidth;
    this.setRightSideWidth(currentWidth === 0 ? targetWidth : 0);
  }

  /**
   * Subscribe to state changes
   * @param {Function} listener - Callback function
   * @returns {Function} Unsubscribe function
   */
  subscribe(listener) {
    this._listeners.add(listener);
    return () => {
      this._listeners.delete(listener);
    };
  }
}

// Create singleton instance
const shellManager = new ShellManager();

// ============================================================================
// Toast Manager (Singleton)
// ============================================================================

/**
 * Toast Manager
 * Singleton that maintains toast state and provides global access for handlers
 * Accessible via Shell.ToastManager for global access
 */
class ToastManager {
  constructor() {
    this._toasts = [];
    this._setToasts = null;
    this._maxToasts = 5;
    this._defaultDuration = 5000;
    this._timeouts = new Map(); // Map of toast ID to timeout ID
    this._pausedTimes = new Map(); // Map of toast ID to remaining time when paused
  }

  /**
   * Initialize toast manager (called by ShellProvider)
   * @param {Function} setToasts - State setter function from ShellProvider
   */
  _init(setToasts) {
    this._setToasts = setToasts;
  }

  /**
   * Generate unique toast ID
   * @returns {string}
   */
  _generateId() {
    return `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * Show a toast notification
   * @param {string} title - Toast title
   * @param {string} [message] - Toast message
   * @param {Object} [options] - Toast options
   * @param {string} [options.type='info'] - Toast type: 'info' | 'success' | 'warning' | 'error'
   * @param {number} [options.duration] - Auto-dismiss duration in ms (default: 5000)
   * @returns {string} Toast ID
   */
  show(title, message = '', options = {}) {
    const {
      type = 'info',
      duration = this._defaultDuration,
      persistToNotifications = true
    } = options;

    const startTime = Date.now();
    const toast = {
      id: this._generateId(),
      title,
      message,
      type,
      duration,
      persistToNotifications,
      timestamp: startTime,
      startTime: startTime // Store start time for pause/resume calculations
    };

    if (!this._setToasts) {
      console.warn('[ToastManager] Toast setter not initialized');
      return toast.id;
    }

    this._setToasts(prev => {
      const updated = [toast, ...prev];
      // Limit max toasts
      return updated.slice(0, this._maxToasts);
    });

    // Auto-dismiss after duration
    if (duration > 0) {
      const timeoutId = setTimeout(() => {
        if (toast.persistToNotifications) {
          notificationCenterManager.addFromToast(toast);
        }
        this.hide(toast.id);
        this._timeouts.delete(toast.id);
      }, duration);
      this._timeouts.set(toast.id, timeoutId);
    }

    return toast.id;
  }

  /**
   * Hide a toast by ID
   * @param {string} id - Toast ID
   */
  hide(id) {
    if (!this._setToasts) {
      console.warn('[ToastManager] Toast setter not initialized');
      return;
    }

    // Clear timeout if exists
    const timeoutId = this._timeouts.get(id);
    if (timeoutId) {
      clearTimeout(timeoutId);
      this._timeouts.delete(id);
    }
    this._pausedTimes.delete(id);

    this._setToasts(prev => prev.filter(toast => toast.id !== id));
  }

  /**
   * Pause auto-dismiss timeout for a toast (e.g., when hovered)
   * @param {string} id - Toast ID
   */
  pauseTimeout(id) {
    const timeoutId = this._timeouts.get(id);
    if (!timeoutId) return; // No active timeout

    if (!this._setToasts) return;

    // Get the toast to calculate remaining time
    let toast = null;
    this._setToasts(prev => {
      toast = prev.find(t => t.id === id);
      return prev;
    });

    if (!toast || !toast.duration || !toast.startTime) return;

    // Calculate elapsed time and remaining time
    const elapsed = Date.now() - toast.startTime;
    const remaining = toast.duration - elapsed;

    if (remaining <= 0) {
      // Time already expired, hide immediately
      this.hide(id);
      return;
    }

    // Clear the current timeout
    clearTimeout(timeoutId);
    this._timeouts.delete(id);
    
    // Store remaining time
    this._pausedTimes.set(id, { remaining });
  }

  /**
   * Resume auto-dismiss timeout for a toast (e.g., when hover ends)
   * @param {string} id - Toast ID
   */
  resumeTimeout(id) {
    const pausedData = this._pausedTimes.get(id);
    if (!pausedData) return; // Wasn't paused

    if (!this._setToasts) return;

    // Get the toast to verify it still exists
    let toast = null;
    this._setToasts(prev => {
      toast = prev.find(t => t.id === id);
      return prev;
    });

    if (!toast || !toast.duration) return;

    // Use the remaining time from when it was paused
    const remaining = pausedData.remaining;

    if (remaining <= 0) {
      // Time already expired, hide immediately
      this.hide(id);
      return;
    }

    // Set new timeout with remaining time
    const timeoutId = setTimeout(() => {
      if (toast.persistToNotifications) {
        notificationCenterManager.addFromToast(toast);
      }
      this.hide(id);
      this._timeouts.delete(id);
    }, remaining);
    
    this._timeouts.set(id, timeoutId);
    this._pausedTimes.delete(id);
  }

  /**
   * Clear all toasts
   */
  clear() {
    if (!this._setToasts) {
      console.warn('[ToastManager] Toast setter not initialized');
      return;
    }

    // Clear all timeouts
    this._timeouts.forEach(timeoutId => clearTimeout(timeoutId));
    this._timeouts.clear();
    this._pausedTimes.clear();

    this._setToasts([]);
  }

  /**
   * Get all active toasts
   * @returns {Array}
   */
  getToasts() {
    return [...this._toasts];
  }

  getNotificationModel() {
    return notificationCenterManager.getModel();
  }

  setNotificationModel(model) {
    notificationCenterManager.setModel(model);
  }

  openNotifications() {
    notificationCenterManager.open();
  }

  closeNotifications() {
    notificationCenterManager.close();
  }

  toggleNotifications() {
    notificationCenterManager.toggle();
  }
}

// Create singleton instance
const toastManager = new ToastManager();

function createDefaultNotificationModel() {
  const now = Date.now();
  return new RecordsModel({
    rows: [
      {
        id: 'welcome-notification',
        title: 'Welcome',
        message: 'Notifications that expire from toast popups will appear here until dismissed.',
        type: 'info',
        timestamp: now,
        created_at: now,
        source: 'system',
        status: 'pending',
        is_read: false,
        resource_path: '/notifications',
        action_label: null,
        action_target: null,
        action_kind: null,
        meta: {}
      }
    ],
    idField: 'id',
    searchFields: ['title', 'message', 'type'],
    summaryDefinitions: [
      { id: 'total', label: 'Pending', type: 'count' }
    ]
  });
}

class NotificationCenterManager {
  constructor() {
    this._open = false;
    this._setOpen = null;
    this._model = createDefaultNotificationModel();
    this._listeners = new Set();
    this._unbindModelListener = null;
    this._bindModelListener();
  }

  _init(setOpen) {
    this._setOpen = setOpen;
  }

  _bindModelListener() {
    if (this._unbindModelListener) {
      this._unbindModelListener();
      this._unbindModelListener = null;
    }

    if (this._model?.subscribe) {
      this._unbindModelListener = this._model.subscribe(() => {
        this._notifyListeners();
      });
    }
  }

  _setOpenState(open) {
    this._open = Boolean(open);
    this._setOpen?.(this._open);
    this._notifyListeners();
  }

  _notifyListeners() {
    this._listeners.forEach((listener) => {
      try {
        listener({
          open: this._open,
          model: this._model
        });
      } catch (error) {
        console.warn('[NotificationCenterManager] Listener failed:', error);
      }
    });
  }

  subscribe(listener) {
    this._listeners.add(listener);
    return () => {
      this._listeners.delete(listener);
    };
  }

  isOpen() {
    return this._open;
  }

  open() {
    this._setOpenState(true);
  }

  close() {
    this._setOpenState(false);
  }

  toggle() {
    this._setOpenState(!this._open);
  }

  getModel() {
    return this._model;
  }

  setModel(model) {
    if (!model) {
      return;
    }

    this._model = model;
    this._bindModelListener();
    this._notifyListeners();
  }

  async addFromToast(toast) {
    if (!toast || !this._model?.createRecord) {
      return;
    }

    const existing = this._model.getRecord ? await this._model.getRecord(toast.id) : null;
    if (existing && this._model.updateRecord) {
      await this._model.updateRecord(toast.id, {
        title: toast.title,
        message: toast.message,
        type: toast.type,
        timestamp: toast.timestamp,
        created_at: toast.timestamp,
        source: 'toast',
        status: 'pending',
        is_read: false,
        resource_path: '/notifications',
        action_label: toast.action_label ?? null,
        action_target: toast.action_target ?? null,
        action_kind: toast.action_kind ?? null,
        meta: toast.meta ?? {}
      });
      return;
    }

    await this._model.createRecord({
      id: toast.id,
      title: toast.title,
      message: toast.message,
      type: toast.type,
      timestamp: toast.timestamp,
      created_at: toast.timestamp,
      source: 'toast',
      status: 'pending',
      is_read: false,
      resource_path: '/notifications',
      action_label: toast.action_label ?? null,
      action_target: toast.action_target ?? null,
      action_kind: toast.action_kind ?? null,
      meta: toast.meta ?? {}
    });
  }

  async dismiss(id) {
    if (!this._model?.deleteRecord) {
      return;
    }

    await this._model.deleteRecord(id);
  }

  async clear() {
    const model = this._model;
    if (!model?.queryRecords || !model?.deleteRecord) {
      return;
    }

    const result = await model.queryRecords({
      offset: 0,
      page_size: 500,
      sort_by: [{ field: 'timestamp', direction: 'desc' }]
    });

    await Promise.all((result.rows || []).map((row) => model.deleteRecord(row.id)));
  }
}

const notificationCenterManager = new NotificationCenterManager();

function getNotificationTypeStyle(type = 'info') {
  return {
    info: {
      backgroundColor: '$blue3',
      borderColor: '$blue8',
      icon: 'info'
    },
    success: {
      backgroundColor: '$green3',
      borderColor: '$green8',
      icon: 'success'
    },
    warning: {
      backgroundColor: '$yellow3',
      borderColor: '$yellow8',
      icon: 'warning'
    },
    error: {
      backgroundColor: '$red3',
      borderColor: '$red8',
      icon: 'error'
    }
  }[type] || {
    backgroundColor: '$blue3',
    borderColor: '$blue8',
    icon: 'info'
  };
}

// ============================================================================
// Shell Provider
// ============================================================================

/**
 * Shell Provider Component
 * Provides shell state and control functions to child components
 * 
 * @param {Object} props
 * @param {React.ReactNode} props.children
 * @param {number} [props.initialLeftWidth=0]
 * @param {number} [props.initialRightWidth=0]
 * @param {number} [props.initialHeaderHeight=0]
 * @param {number} [props.initialFooterHeight=0]
 */
export function ShellProvider({ 
  children, 
  initialLeftWidth = 0, 
  initialRightWidth = 0, 
  initialHeaderHeight = 0, 
  initialFooterHeight = 0 
}) {
  const [leftSideWidth, setLeftSideWidth] = useState(initialLeftWidth);
  const [rightSideWidth, setRightSideWidth] = useState(initialRightWidth);
  const [headerHeight, setHeaderHeight] = useState(initialHeaderHeight);
  const [footerHeight, setFooterHeight] = useState(initialFooterHeight);

  // Toast state
  const [toasts, setToasts] = useState([]);
  const [notificationsOpen, setNotificationsOpen] = useState(notificationCenterManager.isOpen());
  const [networkActivity, setNetworkActivity] = useState(networkActivityManager.getState());

  // Initialize shell manager with setters
  useEffect(() => {
    shellManager._init({
      setLeftSideWidth,
      setRightSideWidth,
      setHeaderHeight,
      setFooterHeight
    });
  }, []);

  // Initialize toast manager with setter
  useEffect(() => {
    toastManager._init(setToasts);
  }, []);

  useEffect(() => {
    notificationCenterManager._init(setNotificationsOpen);
  }, []);

  useEffect(() => networkActivityManager.subscribe(setNetworkActivity), []);

  // Update shell manager state when it changes
  useEffect(() => {
    shellManager._updateState({
      leftSideWidth,
      rightSideWidth,
      headerHeight,
      footerHeight
    });
  }, [leftSideWidth, rightSideWidth, headerHeight, footerHeight]);

  // Toggle functions for convenience
  const toggleLeftSide = useCallback((targetWidth = 250) => {
    setLeftSideWidth(prev => prev === 0 ? targetWidth : 0);
  }, []);

  const toggleRightSide = useCallback((targetWidth = 250) => {
    setRightSideWidth(prev => prev === 0 ? targetWidth : 0);
  }, []);

  // Toast functions
  const showToast = useCallback((title, message = '', options = {}) => {
    return toastManager.show(title, message, options);
  }, []);

  const hideToast = useCallback((id) => {
    toastManager.hide(id);
  }, []);

  const clearToasts = useCallback(() => {
    toastManager.clear();
  }, []);

  const pauseToast = useCallback((id) => {
    toastManager.pauseTimeout(id);
  }, []);

  const resumeToast = useCallback((id) => {
    toastManager.resumeTimeout(id);
  }, []);

  const value = {
    leftSideWidth,
    rightSideWidth,
    headerHeight,
    footerHeight,
    setLeftSideWidth,
    setRightSideWidth,
    setHeaderHeight,
    setFooterHeight,
    toggleLeftSide,
    toggleRightSide,
    toast: {
      show: showToast,
      hide: hideToast,
      clear: clearToasts,
      pause: pauseToast,
      resume: resumeToast,
      toasts
    }
  };

  return (
    <ShellContext.Provider value={value}>
      {children}
      <NetworkActivityOverlay visible={networkActivity.visible} />
      <NotificationCenterPanel open={notificationsOpen} />
    </ShellContext.Provider>
  );
}

// ============================================================================
// Shell Hooks
// ============================================================================

/**
 * Hook to access shell context
 * @returns {Object} Shell state and control functions
 */
export function useShell() {
  const context = useContext(ShellContext);
  if (!context) {
    throw new Error('useShell must be used within a ShellProvider');
  }
  return context;
}

// ============================================================================
// Toast Components
// ============================================================================

/**
 * Toast Component
 * Individual toast notification item
 */
function Toast({ toast, onClose, onPause, onResume }) {
  const [isHovered, setIsHovered] = useState(false);
  const [isExiting, setIsExiting] = useState(false);

  // Pause/resume timeout on hover
  useEffect(() => {
    if (isHovered) {
      onPause?.(toast.id);
    } else {
      onResume?.(toast.id);
    }
  }, [isHovered, toast.id, onPause, onResume]);

  const handleClose = () => {
    setIsExiting(true);
    setTimeout(() => {
      onClose(toast.id);
    }, 300); // Match animation duration
  };

  // Type-specific styling
  const style = getNotificationTypeStyle(toast.type);
  const Icon = getIcon(style.icon);

  return (
    <XStack
      backgroundColor={style.backgroundColor}
      borderWidth={1}
      borderColor={style.borderColor}
      borderRadius="$radiusMd"
      padding="$3"
      minWidth={300}
      maxWidth={400}
      shadowColor="$shadowColor"
      shadowOffset={{ width: 0, height: 2 }}
      shadowOpacity={0.1}
      shadowRadius={8}
      elevation={4}
      gap="$2"
      onPointerEnter={() => setIsHovered(true)}
      onPointerLeave={() => setIsHovered(false)}
      animation="quick"
      opacity={isExiting ? 0 : 1}
      style={{
        transition: 'opacity 0.3s ease, transform 0.3s ease',
        transform: isExiting ? 'translateX(400px)' : 'translateX(0)'
      }}
      role="status"
      aria-live="polite"
    >
      {Icon ? (
        <XStack alignItems="center" justifyContent="center" width={20} height={20} flexShrink={0}>
          <Icon size="md" color="$textSecondary" />
        </XStack>
      ) : null}
      <YStack flex={1} gap="$1">
        {toast.title && (
          <Text fontWeight="600" fontSize="$4" color="$color">
            {toast.title}
          </Text>
        )}
        {toast.message && (
          <Text fontSize="$3" color="$textSecondary">
            {toast.message}
          </Text>
        )}
      </YStack>
      <Button
        size="$2"
        circular
        chromeless
        onPress={handleClose}
        aria-label="Close toast"
      >
        {(() => {
          const CloseIcon = getIcon('close');
          return CloseIcon ? <CloseIcon size="sm" color="$textSecondary" /> : <Text color="$textSecondary">×</Text>;
        })()}
      </Button>
    </XStack>
  );
}

function NotificationRecord({ record, onDismiss }) {
  const style = getNotificationTypeStyle(record.type);
  const Icon = getIcon(style.icon);
  const CloseIcon = getIcon('close');

  return (
    <XStack
      backgroundColor={style.backgroundColor}
      borderWidth={1}
      borderColor={style.borderColor}
      borderRadius="$radiusMd"
      padding="$3"
      gap="$2"
      alignItems="flex-start"
    >
      {Icon ? (
        <XStack alignItems="center" justifyContent="center" width={20} height={20} flexShrink={0} marginTop="$1">
          <Icon size="md" color="$textSecondary" />
        </XStack>
      ) : null}
      <YStack flex={1} gap="$1">
        {record.title ? (
          <Text fontWeight="600" fontSize="$4" color="$color">
            {record.title}
          </Text>
        ) : null}
        {record.message ? (
          <Text fontSize="$3" color="$textSecondary">
            {record.message}
          </Text>
        ) : null}
        {record.timestamp ? (
          <Text fontSize="$2" color="$textMuted">
            {new Date(record.timestamp).toLocaleString()}
          </Text>
        ) : null}
        {record.action_label ? (
          <Text fontSize="$2" color="$accent">
            {record.action_label}
          </Text>
        ) : null}
      </YStack>
      <Button
        size="$2"
        circular
        chromeless
        onPress={() => onDismiss?.(record.id)}
        aria-label="Dismiss notification"
        icon={CloseIcon ? <CloseIcon size="sm" color="$textSecondary" /> : undefined}
      />
    </XStack>
  );
}

function NotificationCenterPanel({ open = false }) {
  const [model, setModel] = useState(notificationCenterManager.getModel());
  const [dataVersion, setDataVersion] = useState(0);
  const [records, setRecords] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  useEffect(() => {
    return notificationCenterManager.subscribe(({ model: nextModel }) => {
      setModel(nextModel);
      setDataVersion((value) => value + 1);
    });
  }, []);

  useEffect(() => {
    if (!model?.subscribe) {
      return undefined;
    }

    return model.subscribe(() => {
      setDataVersion((value) => value + 1);
    });
  }, [model]);

  useEffect(() => {
    let cancelled = false;

    async function loadNotifications() {
      if (!open || !model?.queryRecords) {
        if (!cancelled) {
          setRecords([]);
        }
        return;
      }

      setLoading(true);
      setError('');

      try {
        const result = await model.queryRecords({
          offset: 0,
          page_size: 100,
          sort_by: [{ field: 'timestamp', direction: 'desc' }]
        });

        if (!cancelled) {
          setRecords(result?.rows || []);
        }
      } catch (loadError) {
        if (!cancelled) {
          setError(String(loadError?.message || loadError));
        }
      } finally {
        if (!cancelled) {
          setLoading(false);
        }
      }
    }

    loadNotifications();
    return () => {
      cancelled = true;
    };
  }, [open, model, dataVersion]);

  return (
    <SidePanelShell
      open={open}
      onClose={() => notificationCenterManager.close()}
      title="Notifications"
      width={360}
      toolbar={records.length > 0 ? [
        {
          id: 'clear-notifications',
          label: 'Clear All',
          chromeless: true,
          onPress: () => notificationCenterManager.clear()
        }
      ] : []}
    >
      {error ? (
        <Text color="$danger" fontWeight="600">
          {error}
        </Text>
      ) : null}

      {loading ? (
        <Text color="$textMuted">Loading notifications...</Text>
      ) : null}

      {!loading && records.length === 0 ? (
        <YStack gap="$2">
          <Text fontWeight="600" color="$textPrimary">No pending notifications</Text>
          <Text color="$textMuted">Expired toast messages will appear here until dismissed.</Text>
        </YStack>
      ) : null}

      {records.map((record) => (
        <NotificationRecord
          key={record.id}
          record={record}
          onDismiss={(id) => notificationCenterManager.dismiss(id)}
        />
      ))}
    </SidePanelShell>
  );
}

/**
 * ToastViewport Component
 * Container for toast notifications (fixed bottom-right)
 */
export function ToastViewport() {
  const { toast } = useShell();

  if (!toast || !toast.toasts || toast.toasts.length === 0) {
    return null;
  }

  return (
    <YStack
      position="fixed"
      bottom="$4"
      right="$4"
      gap="$2"
      zIndex={22000}
      pointerEvents="none"
      maxWidth="calc(100vw - 32px)"
    >
      {toast.toasts.map((toastItem) => (
        <XStack
          key={toastItem.id}
          pointerEvents="auto"
        >
          <Toast
            toast={toastItem}
            onClose={toast.hide}
            onPause={toast.pause}
            onResume={toast.resume}
          />
        </XStack>
      ))}
    </YStack>
  );
}

function NetworkActivityOverlay({ visible = false }) {
  if (!visible) {
    return null;
  }

  return (
    <YStack
      role="status"
      aria-live="polite"
      aria-busy
      accessibilityLabel="Network activity in progress"
      position="fixed"
      top={0}
      left={0}
      right={0}
      bottom={0}
      zIndex={21500}
      alignItems="center"
      justifyContent="center"
      pointerEvents="none"
    >
      <YStack
        padding="$4"
        gap="$2"
        alignItems="center"
        justifyContent="center"
        backgroundColor="$bgPanel"
        borderWidth={1}
        borderColor="$lineSubtle"
        borderRadius="$radiusLg"
        shadowColor="$shadowColor"
        shadowOpacity={0.15}
        shadowRadius={12}
        elevation={6}
      >
        <Spinner size="large" color="$accentColor" />
        <Text color="$textSecondary" fontSize="$3">
          Working...
        </Text>
      </YStack>
    </YStack>
  );
}

// ============================================================================
// Shell Placement
// ============================================================================

/**
 * ShellPlacement Component
 * Helper component for placing children in specific shell sections
 * 
 * Usage:
 * <ShellPlacement placement="leftSide">Sidebar content</ShellPlacement>
 * <ShellPlacement placement="header">Header content</ShellPlacement>
 * 
 * @param {Object} props
 * @param {string} props.placement - 'leftSide' | 'rightSide' | 'header' | 'footer' | 'mainContent'
 * @param {React.ReactNode} props.children - Content to place
 */
export function ShellPlacement({ placement = 'mainContent', children }) {
  // Clone children and add placement prop
  return React.Children.map(children, (child) => {
    if (React.isValidElement(child)) {
      return React.cloneElement(child, { 
        placement,
        shellPlacement: placement 
      });
    }
    return child;
  });
}

// ============================================================================
// Exports
// ============================================================================

// Attach static properties
ShellProvider.Manager = shellManager;
ShellProvider.ToastManager = toastManager;
ShellProvider.NotificationManager = notificationCenterManager;
ShellProvider.Context = ShellContext;
ShellProvider.Placement = ShellPlacement;

export default ShellProvider;
export { shellManager as ShellManager, toastManager as ToastManager, notificationCenterManager as NotificationManager };
export { ShellContext };
// ShellPlacement is already exported as a function declaration above

