import React, { useState, useEffect } from 'react';
import { Settings, WifiOff, ArrowRight, ArrowLeft, BookOpen, Download, MousePointerClick } from 'lucide-react';
import { FileItem, FileType, LogEntry, TransferItem, FileSystemState, SiteConfig } from './types';
import FilePane from './components/FilePane';
import LogConsole from './components/LogConsole';
import TransferQueue from './components/TransferQueue';
import SettingsModal from './components/SettingsModal';
import SiteManagerModal from './components/SiteManagerModal';
import { CreateFolderModal, RenameModal, DeleteModal } from './components/FileActionModals';
import { generateLocalFiles } from './utils/mockData';
import { generateRemoteFileList, generateServerMessage } from './services/gemini';

const App: React.FC = () => {
  // --- State ---
  const [connection, setConnection] = useState({
    host: 'ftp.example.com',
    user: 'admin',
    pass: '••••••••',
    port: '21',
    protocol: 'ftp' as 'ftp' | 'sftp',
    passive: true,
    connected: false,
    connecting: false
  });

  const [logs, setLogs] = useState<LogEntry[]>([]);
  const [queue, setQueue] = useState<TransferItem[]>([]);
  const [showSettings, setShowSettings] = useState(false);
  const [showSiteManager, setShowSiteManager] = useState(false);
  const [savedSites, setSavedSites] = useState<SiteConfig[]>([]);
  
  // Modals State
  const [activeModal, setActiveModal] = useState<'create' | 'rename' | 'delete' | null>(null);
  const [modalTargetIsLocal, setModalTargetIsLocal] = useState(true);
  // For Rename
  const [renameTargetName, setRenameTargetName] = useState('');
  
  // Local File System
  const [local, setLocal] = useState<FileSystemState>({
    path: '/',
    files: [],
    isLoading: false
  });
  const [selectedLocalIds, setSelectedLocalIds] = useState<Set<string>>(new Set());

  // Remote File System
  const [remote, setRemote] = useState<FileSystemState>({
    path: '/',
    files: [],
    isLoading: false
  });
  const [selectedRemoteIds, setSelectedRemoteIds] = useState<Set<string>>(new Set());

  // --- Helpers ---
  const addLog = (type: LogEntry['type'], message: string) => {
    setLogs(prev => [...prev, {
      id: Math.random().toString(36),
      timestamp: new Date().toISOString(),
      type,
      message
    }]);
  };

  const getSelectedFiles = (allFiles: FileItem[], ids: Set<string>) => {
      return allFiles.filter(f => ids.has(f.id));
  };

  // --- Backend Download Logic (Updated for SFTP Support) ---
  const handleDownloadBackend = () => {
    const backendCode = `/**
 * WebZilla 백엔드 프록시 서버 (Node.js) v2.0
 * 지원: FTP (basic-ftp), SFTP (ssh2-sftp-client)
 * 
 * 실행 방법:
 * 1. Node.js 설치
 * 2. npm install ws basic-ftp ssh2-sftp-client
 * 3. node backend_proxy.js
 */

const WebSocket = require('ws');
const ftp = require('basic-ftp');
const SftpClient = require('ssh2-sftp-client');
const fs = require('fs');
const path = require('path');
const os = require('os');

// --- 설정 디렉토리 (AppData) ---
function getConfigDir() {
    const homedir = os.homedir();
    if (process.platform === 'win32') {
        return path.join(process.env.APPDATA || path.join(homedir, 'AppData', 'Roaming'), 'WebZilla');
    } else if (process.platform === 'darwin') {
        return path.join(homedir, 'Library', 'Application Support', 'WebZilla');
    } else {
        return path.join(homedir, '.config', 'webzilla');
    }
}
const configDir = getConfigDir();
if (!fs.existsSync(configDir)) {
    try { fs.mkdirSync(configDir, { recursive: true }); } catch (e) {}
}

const wss = new WebSocket.Server({ port: 8080 });
console.log("🚀 WebZilla Proxy Server running on ws://localhost:8080");

wss.on('connection', (ws) => {
    // 클라이언트 상태 관리
    let ftpClient = new ftp.Client();
    let sftpClient = new SftpClient();
    let currentProtocol = 'ftp'; // 'ftp' or 'sftp'
    let isConnected = false;

    ws.on('message', async (message) => {
        try {
            const data = JSON.parse(message);
            
            // --- CONNECT ---
            if (data.command === 'CONNECT') {
                currentProtocol = data.protocol || 'ftp';
                const { host, port, user, pass, passive } = data;
                
                console.log(\`[\${currentProtocol.toUpperCase()}] Connecting to \${user}@\${host}:\${port}\`);
                
                try {
                    if (currentProtocol === 'sftp') {
                        await sftpClient.connect({
                            host,
                            port: parseInt(port) || 22,
                            username: user,
                            password: pass
                        });
                        ws.send(JSON.stringify({ type: 'status', status: 'connected', message: 'SFTP Connected' }));
                    } else {
                        // FTP
                        await ftpClient.access({
                            host,
                            user,
                            password: pass,
                            port: parseInt(port) || 21,
                            secure: false
                        });
                        // 패시브 모드는 basic-ftp에서 기본적으로 자동 처리하지만 명시적 설정이 필요할 수 있음
                        ws.send(JSON.stringify({ type: 'status', status: 'connected', message: 'FTP Connected' }));
                    }
                    isConnected = true;
                } catch (err) {
                    console.error("Connect Error:", err.message);
                    ws.send(JSON.stringify({ type: 'error', message: err.message }));
                }
            }

            // --- LIST ---
            else if (data.command === 'LIST') {
                if (!isConnected) return;
                const listPath = data.path || (currentProtocol === 'sftp' ? '.' : '/');
                
                try {
                    let files = [];
                    if (currentProtocol === 'sftp') {
                        const list = await sftpClient.list(listPath);
                        files = list.map(f => ({
                            name: f.name,
                            type: f.type === 'd' ? 'FOLDER' : 'FILE',
                            size: f.size,
                            date: new Date(f.modifyTime).toISOString(),
                            permissions: f.rights ? f.rights.user + f.rights.group + f.rights.other : ''
                        }));
                    } else {
                        const list = await ftpClient.list(listPath);
                        files = list.map(f => ({
                            name: f.name,
                            type: f.isDirectory ? 'FOLDER' : 'FILE',
                            size: f.size,
                            date: f.rawModifiedAt || new Date().toISOString(),
                            permissions: '-'
                        }));
                    }
                    ws.send(JSON.stringify({ type: 'list', files, path: listPath }));
                } catch (err) {
                    ws.send(JSON.stringify({ type: 'error', message: err.message }));
                }
            }
            
            // --- MKD (Make Directory) ---
            else if (data.command === 'MKD') {
                if (!isConnected) return;
                try {
                   const targetPath = data.path; // Full path
                   if (currentProtocol === 'sftp') {
                       await sftpClient.mkdir(targetPath, true);
                   } else {
                       await ftpClient.ensureDir(targetPath); // ensureDir is safer
                   }
                   ws.send(JSON.stringify({ type: 'success', message: 'Directory created' }));
                } catch(err) {
                   ws.send(JSON.stringify({ type: 'error', message: err.message })); 
                }
            }

            // --- DELE / RMD (Delete) ---
            else if (data.command === 'DELE') {
                if (!isConnected) return;
                // Note: handling single file deletion for simplicity in this snippet
                // In real app, iterate over items
                try {
                   const { path, isFolder } = data;
                   if (currentProtocol === 'sftp') {
                       if (isFolder) await sftpClient.rmdir(path, true);
                       else await sftpClient.delete(path);
                   } else {
                       if (isFolder) await ftpClient.removeDir(path);
                       else await ftpClient.remove(path);
                   }
                   ws.send(JSON.stringify({ type: 'success', message: 'Deleted successfully' }));
                } catch(err) {
                   ws.send(JSON.stringify({ type: 'error', message: err.message })); 
                }
            }
            
            // --- RNFR / RNTO (Rename) ---
            else if (data.command === 'RENAME') {
                 if (!isConnected) return;
                 try {
                     const { from, to } = data;
                     if (currentProtocol === 'sftp') {
                         await sftpClient.rename(from, to);
                     } else {
                         await ftpClient.rename(from, to);
                     }
                     ws.send(JSON.stringify({ type: 'success', message: 'Renamed successfully' }));
                 } catch(err) {
                     ws.send(JSON.stringify({ type: 'error', message: err.message }));
                 }
            }

            // --- DISCONNECT ---
            else if (data.command === 'DISCONNECT') {
                if (currentProtocol === 'sftp') {
                    await sftpClient.end();
                } else {
                    ftpClient.close();
                }
                isConnected = false;
                ws.send(JSON.stringify({ type: 'status', status: 'disconnected' }));
            }
            
            // --- SAVE_SITE (Local Config) ---
            else if (data.command === 'SAVE_SITE') {
                const sitesFile = path.join(configDir, 'sites.json');
                let sites = [];
                if (fs.existsSync(sitesFile)) sites = JSON.parse(fs.readFileSync(sitesFile, 'utf8'));
                // Simple append/replace logic omitted for brevity
                sites.push(data.siteInfo);
                fs.writeFileSync(sitesFile, JSON.stringify(sites, null, 2));
                ws.send(JSON.stringify({ type: 'success', message: 'Site saved locally' }));
            }

        } catch (err) {
            console.error(err);
        }
    });
    
    ws.on('close', () => {
        if (isConnected) {
             if (currentProtocol === 'sftp') sftpClient.end();
             else ftpClient.close();
        }
    });
});
`;
    const blob = new Blob([backendCode], { type: 'text/javascript' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'backend_proxy.js';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    addLog('info', '업데이트된 백엔드 코드(SFTP 지원)가 다운로드되었습니다.');
  };

  // --- Effects ---

  // Initial Load
  useEffect(() => {
    setLocal(prev => ({ ...prev, files: generateLocalFiles('/') }));
    addLog('info', 'WebZilla 클라이언트 v1.1.0 초기화됨');

    const storedSites = localStorage.getItem('webzilla_sites');
    if (storedSites) {
        try {
            setSavedSites(JSON.parse(storedSites));
        } catch (e) { console.error("Failed to load sites", e); }
    }
  }, []);

  // Transfer Simulation Loop
  useEffect(() => {
    const interval = setInterval(() => {
      setQueue(prevQueue => {
        let hasChanges = false;
        const newQueue = prevQueue.map(item => {
          if (item.status === 'transferring') {
            hasChanges = true;
            const step = 5 + Math.random() * 10;
            const newProgress = Math.min(100, item.progress + step);
            
            if (newProgress === 100) {
              addLog('success', `전송 완료: ${item.filename}`);
              return { ...item, progress: 100, status: 'completed' as const, speed: '0 KB/s' };
            }
            return { 
              ...item, 
              progress: newProgress, 
              speed: `${(Math.random() * 500 + 100).toFixed(1)} KB/s` 
            };
          }
          return item;
        });

        // Start next queued item
        const activeCount = newQueue.filter(i => i.status === 'transferring').length;
        if (activeCount < 2) {
            const nextItem = newQueue.find(i => i.status === 'queued');
            if (nextItem) {
                hasChanges = true;
                nextItem.status = 'transferring';
                addLog('info', `전송 시작: ${nextItem.filename}`);
            }
        }
        
        return hasChanges ? newQueue : prevQueue;
      });
    }, 500);

    return () => clearInterval(interval);
  }, []);

  // --- Connection Handlers ---

  const handleConnect = async () => {
    if (connection.connected) {
      setConnection(prev => ({ ...prev, connected: false }));
      addLog('info', '서버 연결이 해제되었습니다.');
      setRemote(prev => ({ ...prev, files: [], path: '/' }));
      setSelectedRemoteIds(new Set());
      return;
    }

    setConnection(prev => ({ ...prev, connecting: true }));
    addLog('command', `CONNECT [${connection.protocol.toUpperCase()}] ${connection.user}@${connection.host}:${connection.port} ${connection.passive ? '(Passive)' : ''}`);

    // Simulation delays
    setTimeout(() => addLog('info', `주소 해석 중: ${connection.host}`), 500);
    setTimeout(() => addLog('success', '연결 성공, 환영 메시지 대기 중...'), 1500);

    // AI generated content
    setTimeout(async () => {
      const welcomeMsg = await generateServerMessage(connection.host);
      addLog('response', welcomeMsg);
      if (connection.protocol === 'ftp') {
        addLog('command', 'USER ' + connection.user);
        addLog('response', '331 Password required');
        addLog('command', 'PASS ******');
        addLog('response', '230 Logged on');
      } else {
        addLog('info', 'SSH2 인증 성공 (SFTP)');
      }
      
      setRemote(prev => ({ ...prev, isLoading: true }));
      
      const files = await generateRemoteFileList(connection.host, '/');
      
      setRemote({
        path: '/',
        files: files,
        isLoading: false
      });

      setConnection(prev => ({ ...prev, connected: true, connecting: false }));
      addLog('success', '디렉토리 목록 조회 완료');
    }, 2500);
  };

  const handleRemoteNavigate = async (path: string) => {
    if (!connection.connected) return;
    setRemote(prev => ({ ...prev, isLoading: true }));
    setSelectedRemoteIds(new Set()); // Clear selection
    addLog('command', `CWD ${path}`);
    
    // Simulate network latency
    setTimeout(async () => {
        addLog('response', '250 Directory successfully changed.');
        addLog('command', 'LIST');
        const files = await generateRemoteFileList(connection.host, path);
        setRemote({
          path,
          files,
          isLoading: false
        });
        addLog('success', '디렉토리 목록 조회 완료');
    }, 800);
  };

  const handleLocalNavigate = (path: string) => {
      setLocal(prev => ({ ...prev, isLoading: true }));
      setSelectedLocalIds(new Set()); // Clear selection
      setTimeout(() => {
        setLocal({
            path,
            files: generateLocalFiles(path),
            isLoading: false
        });
      }, 200);
  };

  // --- File Action Handlers (Triggers Modals) ---

  const initiateCreateFolder = (isLocal: boolean) => {
    if (!isLocal && !connection.connected) return;
    setModalTargetIsLocal(isLocal);
    setActiveModal('create');
  };

  const initiateRename = (isLocal: boolean) => {
    if (!isLocal && !connection.connected) return;
    const selectedIds = isLocal ? selectedLocalIds : selectedRemoteIds;
    if (selectedIds.size !== 1) return;

    const files = isLocal ? local.files : remote.files;
    const file = files.find(f => selectedIds.has(f.id));
    if (file) {
        setRenameTargetName(file.name);
        setModalTargetIsLocal(isLocal);
        setActiveModal('rename');
    }
  };

  const initiateDelete = (isLocal: boolean) => {
    if (!isLocal && !connection.connected) return;
    const selectedIds = isLocal ? selectedLocalIds : selectedRemoteIds;
    if (selectedIds.size === 0) return;
    setModalTargetIsLocal(isLocal);
    setActiveModal('delete');
  };

  // --- Modal Confirm Callbacks ---

  const handleCreateFolderConfirm = (name: string) => {
    if (!name.trim()) return;
    const isLocal = modalTargetIsLocal;
    
    const newItem: FileItem = {
      id: `new-${Date.now()}`,
      name,
      type: FileType.FOLDER,
      size: 0,
      date: new Date().toISOString(),
      permissions: 'drwxr-xr-x'
    };

    if (isLocal) {
      setLocal(prev => ({ ...prev, files: [...prev.files, newItem] }));
      addLog('info', `[로컬] 디렉토리 생성: ${name}`);
    } else {
      setRemote(prev => ({ ...prev, files: [...prev.files, newItem] }));
      addLog('command', `MKD ${name}`);
      addLog('success', `257 "${name}" created`);
    }
    setActiveModal(null);
  };

  const handleRenameConfirm = (newName: string) => {
    if (!newName.trim()) return;
    const isLocal = modalTargetIsLocal;
    const selectedIds = isLocal ? selectedLocalIds : selectedRemoteIds;
    const files = isLocal ? local.files : remote.files;
    const targetFile = files.find(f => selectedIds.has(f.id));
    
    if (!targetFile) return;
    if (targetFile.name === newName) {
        setActiveModal(null);
        return;
    }

    if (isLocal) {
      setLocal(prev => ({
        ...prev,
        files: prev.files.map(f => f.id === targetFile.id ? { ...f, name: newName } : f)
      }));
      addLog('info', `[로컬] 이름 변경: ${targetFile.name} -> ${newName}`);
    } else {
      setRemote(prev => ({
        ...prev,
        files: prev.files.map(f => f.id === targetFile.id ? { ...f, name: newName } : f)
      }));
      addLog('command', `RNFR ${targetFile.name}`);
      addLog('command', `RNTO ${newName}`);
      addLog('success', '250 Rename successful');
    }
    setActiveModal(null);
  };

  const handleDeleteConfirm = () => {
    const isLocal = modalTargetIsLocal;
    const selectedIds = isLocal ? selectedLocalIds : selectedRemoteIds;

    if (isLocal) {
      setLocal(prev => ({ ...prev, files: prev.files.filter(f => !selectedIds.has(f.id)) }));
      setSelectedLocalIds(new Set());
      addLog('info', `[로컬] ${selectedIds.size}개 항목 삭제됨`);
    } else {
      setRemote(prev => ({ ...prev, files: prev.files.filter(f => !selectedIds.has(f.id)) }));
      setSelectedRemoteIds(new Set());
      addLog('command', `DELE [${selectedIds.size} items]`);
      addLog('success', '250 Deleted successfully');
    }
    setActiveModal(null);
  };

  // --- Transfer Logic ---

  const handleUpload = () => {
    if (selectedLocalIds.size === 0 || !connection.connected) return;
    const selectedFiles = getSelectedFiles(local.files, selectedLocalIds);
    const filesToUpload = selectedFiles.filter(f => f.type !== FileType.FOLDER);
    
    if (filesToUpload.length === 0) {
        addLog('error', '업로드할 파일이 없습니다 (폴더 제외)');
        return;
    }

    const newItems: TransferItem[] = filesToUpload.map(f => ({
      id: Math.random().toString(),
      direction: 'upload',
      filename: f.name,
      progress: 0,
      status: 'queued',
      speed: '-'
    }));

    setQueue(prev => [...newItems, ...prev]);
    addLog('info', `${newItems.length}개 파일 업로드 대기`);
  };

  const handleDownload = () => {
    if (selectedRemoteIds.size === 0 || !connection.connected) return;
    const selectedFiles = getSelectedFiles(remote.files, selectedRemoteIds);
    const filesToDownload = selectedFiles.filter(f => f.type !== FileType.FOLDER);

    if (filesToDownload.length === 0) {
        addLog('error', '다운로드할 파일이 없습니다 (폴더 제외)');
        return;
    }

    const newItems: TransferItem[] = filesToDownload.map(f => ({
      id: Math.random().toString(),
      direction: 'download',
      filename: f.name,
      progress: 0,
      status: 'queued',
      speed: '-'
    }));
    
    setQueue(prev => [...newItems, ...prev]);
    addLog('info', `${newItems.length}개 파일 다운로드 대기`);
  };

  // --- Site Manager Handlers ---
  const handleSiteConnect = (site: SiteConfig) => {
      setConnection({
          host: site.host,
          port: site.port,
          user: site.user,
          pass: site.pass || '',
          protocol: site.protocol,
          passive: site.passiveMode !== false,
          connected: false,
          connecting: false
      });
      setShowSiteManager(false);
      setTimeout(() => handleConnect(), 100);
  };

  // --- Render ---

  // Prepare data for Delete Modal
  const getDeleteModalData = () => {
      const isLocal = modalTargetIsLocal;
      const ids = isLocal ? selectedLocalIds : selectedRemoteIds;
      const files = isLocal ? local.files : remote.files;
      const selectedFiles = files.filter(f => ids.has(f.id));
      return {
          count: ids.size,
          names: selectedFiles.map(f => f.name)
      };
  };

  return (
    <div className="flex flex-col h-screen bg-slate-50 text-slate-800 font-sans">
      {/* Modals */}
      <SettingsModal isOpen={showSettings} onClose={() => setShowSettings(false)} />
      <SiteManagerModal 
        isOpen={showSiteManager} 
        onClose={() => setShowSiteManager(false)}
        initialSites={savedSites}
        onSaveSites={(sites) => {
            setSavedSites(sites);
            localStorage.setItem('webzilla_sites', JSON.stringify(sites));
        }}
        onConnect={handleSiteConnect}
      />
      
      <CreateFolderModal 
        isOpen={activeModal === 'create'} 
        onClose={() => setActiveModal(null)} 
        onConfirm={handleCreateFolderConfirm} 
      />
      <RenameModal 
        isOpen={activeModal === 'rename'}
        currentName={renameTargetName}
        onClose={() => setActiveModal(null)}
        onConfirm={handleRenameConfirm}
      />
      <DeleteModal 
        isOpen={activeModal === 'delete'}
        fileCount={getDeleteModalData().count}
        fileNames={getDeleteModalData().names}
        onClose={() => setActiveModal(null)}
        onConfirm={handleDeleteConfirm}
      />

      {/* 1. Header & Quick Connect */}
      <header className="bg-white border-b border-slate-200 p-2 shadow-sm z-20">
        <div className="flex flex-col xl:flex-row gap-4 items-center">
          <div className="flex items-center gap-2 shrink-0">
             <div className="w-8 h-8 bg-blue-600 rounded flex items-center justify-center font-bold text-white shadow-lg shadow-blue-500/20">WZ</div>
             <span className="font-bold text-lg tracking-tight hidden sm:inline text-slate-700">웹질라</span>
          </div>
          
          <div className="flex-1 w-full flex flex-wrap items-center gap-2">
            
            {/* Site Manager Trigger */}
            <button 
              onClick={() => setShowSiteManager(true)}
              className="h-[46px] flex flex-col items-center justify-center px-3 gap-0.5 rounded bg-white hover:bg-slate-50 border border-slate-300 text-[10px] font-semibold text-slate-600 transition-colors shadow-sm"
              title="사이트 관리자"
            >
                <BookOpen size={16} className="text-blue-600" />
                <span>사이트</span>
            </button>

            <div className="w-px h-8 bg-slate-200 mx-1"></div>

            {/* Quick Connect Inputs */}
            <div className="flex flex-col gap-0.5">
              <label className="text-[10px] text-slate-500 font-semibold pl-1">호스트</label>
              <input 
                type="text" 
                value={connection.host}
                onChange={(e) => setConnection(c => ({...c, host: e.target.value}))}
                className="w-48 h-[30px] bg-white border border-slate-300 rounded px-2 text-sm focus:border-blue-500 focus:outline-none placeholder:text-slate-400 shadow-sm"
                placeholder="ftp.example.com"
              />
            </div>

            <div className="flex flex-col gap-0.5">
              <label className="text-[10px] text-slate-500 font-semibold pl-1">사용자</label>
              <input 
                type="text" 
                value={connection.user}
                onChange={(e) => setConnection(c => ({...c, user: e.target.value}))}
                className="w-32 h-[30px] bg-white border border-slate-300 rounded px-2 text-sm focus:border-blue-500 focus:outline-none shadow-sm"
              />
            </div>

            <div className="flex flex-col gap-0.5">
              <label className="text-[10px] text-slate-500 font-semibold pl-1">비밀번호</label>
              <input 
                type="password" 
                value={connection.pass}
                onChange={(e) => setConnection(c => ({...c, pass: e.target.value}))}
                className="w-32 h-[30px] bg-white border border-slate-300 rounded px-2 text-sm focus:border-blue-500 focus:outline-none shadow-sm"
              />
            </div>

            <div className="flex flex-col gap-0.5">
              <label className="text-[10px] text-slate-500 font-semibold pl-1">포트</label>
              <div className="flex items-center gap-3">
                <input 
                    type="text" 
                    value={connection.port}
                    onChange={(e) => setConnection(c => ({...c, port: e.target.value}))}
                    className="w-16 h-[30px] bg-white border border-slate-300 rounded px-2 text-sm text-center focus:border-blue-500 focus:outline-none shadow-sm"
                />
                
                {/* Passive Mode Toggle Switch */}
                <div className="flex flex-col items-center justify-center -mb-4">
                     <label className="relative inline-flex items-center cursor-pointer group" title="패시브 모드 (Passive Mode)">
                        <input 
                            type="checkbox" 
                            className="sr-only peer" 
                            checked={connection.passive}
                            onChange={(e) => setConnection(c => ({...c, passive: e.target.checked}))}
                        />
                        <div className="w-9 h-5 bg-slate-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600"></div>
                        <span className="ml-1.5 text-[10px] font-medium text-slate-500 group-hover:text-slate-700">Passive</span>
                    </label>
                </div>
              </div>
            </div>

            <div className="flex-1"></div>

            {/* Connect & Options */}
            <div className="flex items-end gap-2 pb-0.5">
               <button 
                onClick={handleConnect}
                disabled={connection.connecting}
                className={`px-4 h-[30px] flex items-center justify-center gap-2 rounded font-semibold text-sm transition-all shadow-md ${
                  connection.connected 
                    ? 'bg-red-50 text-red-600 border border-red-200 hover:bg-red-100'
                    : 'bg-blue-600 text-white hover:bg-blue-500 shadow-blue-500/20'
                }`}
               >
                 {connection.connecting ? <div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" /> : (connection.connected ? <><WifiOff size={16} /> 연결 해제</> : '빠른 연결')}
               </button>
               
               <div className="relative">
                   <button 
                    onClick={handleDownloadBackend}
                    className={`h-[30px] flex items-center justify-center px-3 rounded bg-emerald-600 hover:bg-emerald-500 text-white border border-emerald-500 shadow-md shadow-emerald-500/20 transition-all ${!connection.connected ? 'animate-pulse ring-2 ring-emerald-400/50' : ''}`}
                    title="백엔드 코드(SFTP 지원) 다운로드"
                   >
                     <Download size={14} className="mr-1.5" /> 백엔드
                   </button>
                   {!connection.connected && (
                       <span className="absolute -top-1 -right-1 flex h-2 w-2">
                         <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
                         <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
                       </span>
                   )}
               </div>

               <button 
                onClick={() => setShowSettings(true)}
                className="w-[30px] h-[30px] flex items-center justify-center rounded bg-white border border-slate-300 text-slate-600 hover:text-slate-900 hover:bg-slate-50 shadow-sm"
                title="설정"
               >
                 <Settings size={16} />
               </button>
            </div>
          </div>
        </div>
      </header>

      {/* 2. Log View & Sponsor Area */}
      <div className="h-32 shrink-0 p-2 pb-0 flex gap-2">
        <div className="w-1/2 min-w-0 h-full">
            <LogConsole logs={logs} />
        </div>
        <div className="w-1/2 min-w-0 h-full bg-white border border-slate-300 rounded-lg shadow-sm flex flex-col items-center justify-center relative overflow-hidden group cursor-pointer">
            <div className="absolute top-0 right-0 bg-slate-100 text-[9px] text-slate-500 px-1.5 py-0.5 rounded-bl border-b border-l border-slate-200 z-10">
                SPONSORED
            </div>
            <div className="text-slate-300 flex flex-col items-center gap-1 group-hover:text-slate-400 transition-colors">
                <div className="font-bold text-lg tracking-widest flex items-center gap-2">
                     <MousePointerClick size={20} /> GOOGLE ADSENSE
                </div>
                <div className="text-xs">Premium Ad Space Available</div>
            </div>
            {/* Pattern background for placeholder effect */}
            <div className="absolute inset-0 -z-0 opacity-30" style={{ backgroundImage: 'radial-gradient(#cbd5e1 1px, transparent 1px)', backgroundSize: '10px 10px' }}></div>
        </div>
      </div>

      {/* 3. Main Split View */}
      <div className="flex-1 flex flex-col md:flex-row min-h-0 p-2 gap-2">
        
        {/* Local Pane */}
        <div className="flex-1 min-h-0 flex flex-col min-w-[300px]">
          <FilePane 
            title="로컬 사이트" 
            icon="local"
            path={local.path}
            files={local.files}
            isLoading={local.isLoading}
            onNavigate={handleLocalNavigate}
            onNavigateUp={() => handleLocalNavigate(local.path.split('/').slice(0, -1).join('/') || '/')}
            onSelectionChange={setSelectedLocalIds}
            selectedIds={selectedLocalIds}
            connected={true}
            onCreateFolder={() => initiateCreateFolder(true)}
            onDelete={() => initiateDelete(true)}
            onRename={() => initiateRename(true)}
          />
        </div>

        {/* Middle Actions */}
        <div className="flex md:flex-col items-center justify-center gap-2 p-1">
            <button 
                onClick={handleUpload}
                disabled={selectedLocalIds.size === 0 || !connection.connected}
                className="p-3 bg-white border border-slate-300 shadow-sm rounded hover:bg-blue-50 hover:text-blue-600 hover:border-blue-300 transition-colors disabled:opacity-30 disabled:cursor-not-allowed text-slate-400 group relative"
            >
                <div className="absolute left-1/2 -top-8 -translate-x-1/2 bg-slate-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-50 shadow-lg">업로드</div>
                <ArrowRight size={24} strokeWidth={2.5} />
            </button>
            <button 
                onClick={handleDownload}
                disabled={selectedRemoteIds.size === 0 || !connection.connected}
                className="p-3 bg-white border border-slate-300 shadow-sm rounded hover:bg-green-50 hover:text-green-600 hover:border-green-300 transition-colors disabled:opacity-30 disabled:cursor-not-allowed text-slate-400 group relative"
            >
                <div className="absolute left-1/2 -top-8 -translate-x-1/2 bg-slate-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-50 shadow-lg">다운로드</div>
                <ArrowLeft size={24} strokeWidth={2.5} />
            </button>
        </div>

        {/* Remote Pane */}
        <div className="flex-1 min-h-0 flex flex-col min-w-[300px]">
          <FilePane 
             title={`리모트 사이트: ${connection.host}`}
             icon="remote"
             path={remote.path}
             files={remote.files}
             isLoading={remote.isLoading}
             onNavigate={handleRemoteNavigate}
             onNavigateUp={() => handleRemoteNavigate(remote.path.split('/').slice(0, -1).join('/') || '/')}
             onSelectionChange={setSelectedRemoteIds}
             selectedIds={selectedRemoteIds}
             connected={connection.connected}
             onCreateFolder={() => initiateCreateFolder(false)}
             onDelete={() => initiateDelete(false)}
             onRename={() => initiateRename(false)}
          />
        </div>
      </div>

      {/* 4. Queue / Status */}
      <div className="h-48 shrink-0 p-2 pt-0">
        <TransferQueue queue={queue} />
      </div>

      {/* Footer */}
      <footer className="bg-white border-t border-slate-200 px-3 py-1 text-[10px] text-slate-500 flex justify-between shadow-[0_-2px_10px_rgba(0,0,0,0.02)]">
        <span>WebZilla v1.1.0 - React/TypeScript Demo</span>
        <div className="flex gap-4">
            <span>Server: {connection.connected ? 'Connected' : 'Disconnected'}</span>
            <span>Protocol: {connection.protocol.toUpperCase()} {connection.passive ? '(Passive)' : ''}</span>
        </div>
      </footer>
    </div>
  );
};

export default App;