
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { Playlist, ServerType, SyncStrategy, PlexServerConnection, RegexReplacement } from './types';
import { apiService } from './services/api';
import ServerPanel from './components/ServerPanel';
import StrategySelector from './components/StrategySelector';
import ConnectionModal from './components/ConnectionModal';
import { ArrowLeftRight, ShieldCheck, X, Server, ServerOff } from 'lucide-react';

interface Toast {
  id: number;
  message: string;
  exiting: boolean;
  entering: boolean;
}

const App: React.FC = () => {
  const [localPlaylists, setLocalPlaylists] = useState<Playlist[]>([]);
  const [cloudPlaylists, setCloudPlaylists] = useState<Playlist[]>([]);
  const [cloudServerInfo, setCloudServerInfo] = useState<PlexServerConnection | undefined>(undefined);

  const [loadingLocal, setLoadingLocal] = useState(false);
  const [loadingCloud, setLoadingCloud] = useState(false);
  const [statusIntervalMs, setStatusIntervalMs] = useState<number>(60000);

  // Connection Modal State
  const [isConnectionModalOpen, setIsConnectionModalOpen] = useState(false);

  // Strategy State
  const [currentStrategy, setCurrentStrategy] = useState<SyncStrategy>(SyncStrategy.LOCAL_OVERWRITE);
  
  // Regex State
  const [regexReplacements, setRegexReplacements] = useState<RegexReplacement[]>([]);

  // Toast Notification System
  const [toasts, setToasts] = useState<Toast[]>([]);
  const timeoutsRef = useRef<{[key: number]: ReturnType<typeof setTimeout>}>({});

  const removeToast = (id: number) => {
    setToasts(prev => prev.filter(t => t.id !== id));
    if (timeoutsRef.current[id]) {
      clearTimeout(timeoutsRef.current[id]);
      delete timeoutsRef.current[id];
    }
  };

  const addToast = (message: string) => {
    const id = Date.now();
    // Start with entering: true to position it above
    const newToast: Toast = { id, message, exiting: false, entering: true };
    
    setToasts(prev => {
      // Mark all existing toasts as exiting immediately so they slide up
      const exitingToasts = prev.map(t => ({ ...t, exiting: true, entering: false }));
      return [...exitingToasts, newToast];
    });

    // Auto dismiss the new toast after 3 seconds
    const dismissTimer = setTimeout(() => {
      setToasts(prev => prev.map(t => t.id === id ? { ...t, exiting: true } : t));
    }, 3000);
    
    timeoutsRef.current[id] = dismissTimer;
  };

  // Effect to trigger the "slide down" animation
  useEffect(() => {
    const enteringIds = toasts.filter(t => t.entering).map(t => t.id);
    
    if (enteringIds.length > 0) {
      let raf1: number;
      let raf2: number;

      raf1 = requestAnimationFrame(() => {
        raf2 = requestAnimationFrame(() => {
          setToasts(prev => prev.map(t => 
            enteringIds.includes(t.id) ? { ...t, entering: false } : t
          ));
        });
      });
      
      return () => {
        cancelAnimationFrame(raf1);
        cancelAnimationFrame(raf2);
      };
    }
  }, [toasts]);

  // Cleanup effect for exiting toasts
  useEffect(() => {
    const exitingToasts = toasts.filter(t => t.exiting);
    exitingToasts.forEach(t => {
      if (!timeoutsRef.current[`remove-${t.id}`]) {
        timeoutsRef.current[`remove-${t.id}`] = setTimeout(() => {
          removeToast(t.id);
          delete timeoutsRef.current[`remove-${t.id}`];
        }, 300);
      }
    });
  }, [toasts]);

  // Fetch Local Playlists
  const refreshLocal = useCallback(async () => {
    setLoadingLocal(true);
    const result = await apiService.getPlaylists(ServerType.LOCAL);
    if (result.status === 'success') {
      setLocalPlaylists(result.data);
    }
    setLoadingLocal(false);
  }, []);

  // Fetch Cloud Playlists and Info
  const refreshCloud = useCallback(async () => {
    setLoadingCloud(true);
    // Fetch playlists
    const playlistResult = await apiService.getPlaylists(ServerType.CLOUD);
    if (playlistResult.status === 'success') {
      setCloudPlaylists(playlistResult.data);
    } else {
      setCloudPlaylists([]);
    }

    // Fetch server info
    const infoResult = await apiService.getServerStatus();
    if (infoResult.status === 'success') {
      setCloudServerInfo(infoResult.data);
    } else {
      setCloudServerInfo({ isConnected: false });
    }

    setLoadingCloud(false);
  }, []);

  // Initial Load
  useEffect(() => {
    const loadSettings = async () => {
      const [settings, uiConfig] = await Promise.all([
        apiService.getSettings(),
        apiService.getUiConfig()
      ]);

      if (settings.status === 'success') {
        setCurrentStrategy(normalizeStrategy(settings.data.syncStrategy));
        if (settings.data.regexRules) {
          setRegexReplacements(settings.data.regexRules);
        }
      }

      if (uiConfig.status === 'success') {
        const ms = Math.max(10000, (uiConfig.data.statusCheckIntervalSeconds || 60) * 1000);
        setStatusIntervalMs(ms);
      }

      refreshLocal();
      refreshCloud();
    };

    loadSettings();
  }, [refreshLocal, refreshCloud]);

  // Periodically check cloud connection status to avoid stale UI loops
  useEffect(() => {
    const timer = window.setInterval(() => {
      refreshCloud();
    }, statusIntervalMs);

    return () => window.clearInterval(timer);
  }, [refreshCloud, statusIntervalMs]);

  const normalizeStrategy = (value?: string): SyncStrategy => {
    if (!value) return SyncStrategy.LOCAL_OVERWRITE;
    const values = Object.values(SyncStrategy);
    return values.includes(value as SyncStrategy)
      ? (value as SyncStrategy)
      : SyncStrategy.LOCAL_OVERWRITE;
  };

  // Handle Strategy Change
  const handleStrategyChange = async (strategy: SyncStrategy, label: string) => {
    setCurrentStrategy(strategy);
    const result = await apiService.saveStrategy(strategy);
    if (result.status === 'success') {
      addToast(`Selected strategy "${label}" has been saved.`);
    } else {
      addToast('Failed to save strategy to server.');
    }
  };

  // Handle Regex Save
  const handleSaveRegex = async (replacements: RegexReplacement[]) => {
    const result = await apiService.saveRegexRules(replacements);
    if (result.status === 'success') {
      setRegexReplacements(result.data);
      addToast('Regex preprocessing rules have been saved.');
    } else {
      addToast(result.message || 'Failed to save regex rules.');
    }
  };

  const handleConnectSuccess = (serverInfo: PlexServerConnection) => {
    setCloudServerInfo(serverInfo);
    // Removed implicit toast here to allow the caller (ConnectionModal) to handle specific messaging
    refreshCloud(); // Refresh playlists after new connection
  };

  const getToastStyles = (toast: Toast): React.CSSProperties => {
    if (toast.exiting || toast.entering) {
      return {
        opacity: 0,
        transform: 'translateY(-40px) scale(0.95)',
      };
    }
    return {
      opacity: 1,
      transform: 'translateY(0) scale(1)',
    };
  };

  const getToastClasses = () => {
    return "absolute top-2 flex items-center space-x-2 px-4 py-2 rounded-full shadow-lg border text-sm font-medium pointer-events-auto bg-gray-800 text-plex-orange border-plex-orange/30 transition-all duration-300 ease-out origin-top z-50 backdrop-blur-md";
  };

  const isConnected = cloudServerInfo?.isConnected;

  return (
    <div className="min-h-screen flex flex-col bg-gray-900 text-gray-100 font-sans overflow-hidden bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-gray-800 via-gray-900 to-black">
      
      {/* App Header */}
      <header className="flex-none bg-gray-800/80 border-b border-white/5 shadow-md z-20 relative backdrop-blur-md">
        <div className="max-w-7xl mx-auto px-4 md:px-6 h-16 flex items-center justify-between">
          <div className="flex items-center space-x-3">
            <div className="bg-gradient-to-br from-plex-orange to-yellow-600 p-1.5 rounded-lg text-gray-900 shadow-lg shadow-plex-orange/20">
              <ArrowLeftRight size={24} strokeWidth={2.5} />
            </div>
            <h1 className="text-xl font-bold tracking-tight text-white">
              Plex<span className="text-plex-orange">Sync</span>
            </h1>
          </div>
          
          {/* Connection Status Button */}
          <button 
            onClick={() => setIsConnectionModalOpen(true)}
            className={`flex items-center justify-center w-9 h-9 rounded-full border transition-all duration-300 hover:scale-105 active:scale-95 shadow-md ${
              isConnected 
                ? 'bg-green-500/10 border-green-500/50 text-green-400 hover:bg-green-500/20 hover:shadow-green-500/20' 
                : 'bg-red-500/10 border-red-500/50 text-red-400 hover:bg-red-500/20 hover:shadow-red-500/20'
            }`}
            title={isConnected ? "Connected to Plex" : "Disconnected"}
          >
            {isConnected ? <Server size={18} /> : <ServerOff size={18} />}
          </button>
        </div>
      </header>

      {/* Notification Toasts Container */}
      <div className="fixed top-20 left-0 right-0 flex justify-center h-0 overflow-visible z-[100] pointer-events-none">
        {toasts.map((toast) => (
          <div 
            key={toast.id}
            className={getToastClasses()}
            style={getToastStyles(toast)}
          >
              <ShieldCheck size={16} />
              <span>{toast.message}</span>
              <button 
                onClick={() => setToasts(prev => prev.map(t => t.id === toast.id ? { ...t, exiting: true } : t))}
                className="ml-2 hover:text-white transition-colors"
              >
                <X size={14} />
              </button>
          </div>
        ))}
      </div>

      {/* Main Content Area */}
      <main className="flex-1 overflow-hidden relative z-10">
        <div className="absolute inset-0 flex flex-col md:flex-row max-w-7xl mx-auto p-4 md:p-6 gap-3 md:gap-6">
          
          {/* Left Column - Local */}
          <div className="flex-1 min-h-0 h-full w-full">
            <ServerPanel 
              type={ServerType.LOCAL}
              playlists={localPlaylists}
              isLoading={loadingLocal}
              onRefresh={refreshLocal}
            />
          </div>

          {/* Strategy Selector - Positioned specifically between headers */}
          {/* Desktop: Centered Horizontally, Top aligned with Headers (Padding Top 24px + Header Half Height ~40px = ~64px) */}
          {/* Mobile: Centered Vertically, Right aligned with Headers (Padding Right 16px + Header Half Width ~36px = ~52px) */}
          <div className="absolute 
              z-30
              /* Mobile Positioning: Center Vertically, Anchored Right */
              top-1/2 right-[52px] transform translate-x-1/2 -translate-y-1/2
              
              /* Desktop Positioning: Center Horizontally, Anchored Top */
              md:top-[64px] md:right-auto md:left-1/2 md:transform md:-translate-x-1/2 md:-translate-y-1/2"
          >
              <StrategySelector 
                currentStrategy={currentStrategy}
                onSelect={handleStrategyChange}
                savedRegexReplacements={regexReplacements}
                onSaveRegex={handleSaveRegex}
              />
          </div>

          {/* Right Column - Cloud */}
          <div className="flex-1 min-h-0 h-full w-full">
            <ServerPanel 
              type={ServerType.CLOUD}
              playlists={cloudPlaylists}
              isLoading={loadingCloud}
              onRefresh={refreshCloud}
              serverInfo={cloudServerInfo}
            />
          </div>

        </div>
      </main>
      
      {/* Footer */}
      <footer className="flex-none py-4 text-center text-xs text-gray-600 border-t border-white/5 bg-gray-900/50 backdrop-blur">
        <p>&copy; {new Date().getFullYear()} PlexSync Manager. Connected to Docker backend.</p>
      </footer>

      {/* Modals */}
      <ConnectionModal 
        isOpen={isConnectionModalOpen} 
        onClose={() => setIsConnectionModalOpen(false)}
        onConnectSuccess={handleConnectSuccess}
        onShowMessage={addToast}
      />
    </div>
  );
};

export default App;
