/**
 * 관리자 페이지
 * - 탭 UI: 콘솔 / 플레이어 / 설정
 */

import { useEffect, useState, useRef, useCallback } from 'react';
import { useNavigate, useLocation, Link } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import { 
  Shield, ArrowLeft, ArrowDown, Loader2, Terminal, Users, Settings,
  Send, Ban, UserX, Crown, Sun, Moon, Cloud, CloudRain, CloudLightning,
  ChevronDown, FileText, Download, Trash2, Check, RefreshCw, Eye, X
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { io } from 'socket.io-client';
import Tooltip from '../components/Tooltip';

// 더미 로그 데이터
const DUMMY_LOGS = [
  { time: '15:01:23', type: 'info', message: '[Server] Starting minecraft server version 1.21.1' },
  { time: '15:01:24', type: 'info', message: '[Server] Loading properties' },
  { time: '15:01:25', type: 'info', message: '[Server] Preparing level "world"' },
  { time: '15:01:28', type: 'info', message: '[Server] Done (3.245s)! For help, type "help"' },
  { time: '15:05:12', type: 'info', message: '[Server] 비머[/127.0.0.1:54321] logged in' },
  { time: '15:05:15', type: 'info', message: '[Server] 비머 joined the game' },
  { time: '15:10:30', type: 'warning', message: '[Server] Can\'t keep up! Is the server overloaded?' },
  { time: '15:15:00', type: 'info', message: '[Server] 비머부캐 joined the game' },
];

// 더미 로그 파일 데이터 (삭제됨 - API 사용)

// 더미 게임규칙 데이터 제거됨 - 소켓에서 실시간으로 가져옴

export default function Admin({ isMobile = false }) {
  const { isLoggedIn, isAdmin, user, loading } = useAuth();
  const navigate = useNavigate();
  const location = useLocation();
  const [toast, setToast] = useState(null);
  
  // 탭 상태
  const [activeTab, setActiveTab] = useState('console');
  
  // 콘솔 관련 상태
  const [logs, setLogs] = useState([]);
  const [command, setCommand] = useState('');
  const [logFiles, setLogFiles] = useState([]);
  const [logServers, setLogServers] = useState([]); // 서버 ID 목록
  const [selectedLogServer, setSelectedLogServer] = useState('all'); // 선택된 서버
  const [selectedLogType, setSelectedLogType] = useState('all'); // 로그 종류 필터
  const [logViewerOpen, setLogViewerOpen] = useState(false); // 로그 뷰어 다이얼로그
  const [viewingLog, setViewingLog] = useState(null); // 보고 있는 로그 파일
  const [logContent, setLogContent] = useState(''); // 로그 내용
  const [logLoading, setLogLoading] = useState(false); // 로그 로딩
  const [serverDropdownOpen, setServerDropdownOpen] = useState(false); // 서버 드롭다운
  const [typeDropdownOpen, setTypeDropdownOpen] = useState(false); // 타입 드롭다운
  const logEndRef = useRef(null);
  const logContainerRef = useRef(null);
  const isInitialLoad = useRef(true);
  const [isAtBottom, setIsAtBottom] = useState(true); // 스크롤이 맨 아래에 있는지 추적
  
  // 명령어 히스토리
  const [commandHistory, setCommandHistory] = useState([]);
  const [historyIndex, setHistoryIndex] = useState(-1);
  
  // 플레이어 관련 상태
  const [players, setPlayers] = useState([]);
  const [banList, setBanList] = useState([]); // 밴 목록
  const [playerFilter, setPlayerFilter] = useState('all'); // all, online, offline, banned
  const [selectedPlayer, setSelectedPlayer] = useState(null);
  const [showPlayerDialog, setShowPlayerDialog] = useState(false);
  const [dialogAction, setDialogAction] = useState(null); // kick, ban, op, unban
  const [actionReason, setActionReason] = useState('');
  
  // 설정 관련 상태
  const [gameRules, setGameRules] = useState({}); // 소켓에서 가져온 게임 규칙
  const [gameRuleDescriptions, setGameRuleDescriptions] = useState({}); // 게임 규칙 설명
  const [difficulty, setDifficulty] = useState('normal');
  const [timeOfDay, setTimeOfDay] = useState('day');
  const [weather, setWeather] = useState('clear');

  // 권한 확인
  useEffect(() => {
    if (!loading) {
      if (!isLoggedIn) {
        navigate('/login', { state: { from: location.pathname } });
      } else if (!isAdmin) {
        setToast('관리자 권한이 필요합니다.');
        setTimeout(() => navigate('/'), 1500);
      }
    }
  }, [isLoggedIn, isAdmin, loading, navigate, location.pathname]);

  // 토스트 자동 숨기기
  useEffect(() => {
    if (toast) {
      const timer = setTimeout(() => setToast(null), 3000);
      return () => clearTimeout(timer);
    }
  }, [toast]);

  // 플레이어 목록 fetch (안정적인 참조)
  const fetchPlayers = useCallback(async () => {
    try {
      const token = localStorage.getItem('token');
      const response = await fetch('/api/admin/players', {
        headers: { 'Authorization': `Bearer ${token}` }
      });
      const data = await response.json();
      if (data.players) {
        setPlayers(data.players);
      }
    } catch (error) {
      console.error('플레이어 목록 조회 실패:', error);
    }
  }, []);

  // 밴 목록 fetch (안정적인 참조)
  const fetchBanList = useCallback(async () => {
    try {
      const token = localStorage.getItem('token');
      const response = await fetch('/api/admin/banlist', {
        headers: { 'Authorization': `Bearer ${token}` }
      });
      const data = await response.json();
      if (data.banList) {
        setBanList(data.banList);
      }
    } catch (error) {
      console.error('밴 목록 조회 실패:', error);
    }
  }, []);

  // 플레이어 탭 활성화 시 데이터 로드
  useEffect(() => {
    if (activeTab === 'players' && isAdmin) {
      fetchPlayers();
      fetchBanList();
    }
  }, [activeTab, isAdmin]);

  // 스크롤 위치가 맨 아래인지 확인하는 함수
  const checkIsAtBottom = useCallback((container) => {
    if (!container) return true;
    // 5px 오차 허용 (스크롤 정밀도 문제 대응)
    return container.scrollHeight - container.scrollTop - container.clientHeight < 5;
  }, []);

  // 스크롤 이벤트 핸들러 - isAtBottom 상태 업데이트
  const handleLogScroll = useCallback((e) => {
    const container = e.target;
    setIsAtBottom(checkIsAtBottom(container));
  }, [checkIsAtBottom]);

  // 맨 아래로 스크롤하는 함수
  const scrollToBottom = useCallback(() => {
    const container = logContainerRef.current;
    if (container) {
      container.scrollTop = container.scrollHeight;
      setIsAtBottom(true);
    }
  }, []);

  // 로그 스크롤 - 새 로그 추가 시 부드럽게 스크롤 (맨 아래에 있을 때만)
  // CSS scroll-behavior: smooth가 컨테이너에 적용되어 있으므로 scrollTop 설정만으로 부드럽게 동작
  useEffect(() => {
    if (activeTab !== 'console' || logs.length === 0) return;
    
    const container = logContainerRef.current;
    if (!container) return;
    
    if (isInitialLoad.current) {
      // 초기 로드 시 즉시 스크롤 (애니메이션 없이)
      container.style.scrollBehavior = 'auto';
      container.scrollTop = container.scrollHeight;
      setIsAtBottom(true);
      requestAnimationFrame(() => {
        container.style.scrollBehavior = 'smooth';
      });
      isInitialLoad.current = false;
    } else if (isAtBottom) {
      // 맨 아래에 있을 때만 새 로그에 따라 자동 스크롤
      container.scrollTop = container.scrollHeight;
    }
  }, [logs, activeTab, isAtBottom]);

  // 탭 전환 시 맨 아래로 스크롤 (ref 콜백 방식)
  // AnimatePresence로 인해 컴포넌트가 리마운트될 때 useEffect가 다시 트리거되지 않으므로
  // ref 콜백을 사용하여 DOM이 마운트될 때마다 스크롤 처리
  // 주의: logs.length를 의존성에서 제거하여 새 로그 추가 시에는 위의 useEffect에서 부드럽게 스크롤
  const setLogContainerRef = useCallback((node) => {
    logContainerRef.current = node;
    if (node) {
      // DOM 마운트 시 (탭 전환 시) 즉시 맨 아래로 스크롤
      // CSS smooth가 설정되어 있으므로 일시적으로 비활성화
      requestAnimationFrame(() => {
        node.style.scrollBehavior = 'auto'; // 즉시 스크롤
        node.scrollTop = node.scrollHeight;
        setIsAtBottom(true);
        // 다음 프레임에서 smooth 복원 (새 로그 추가 시 부드럽게)
        requestAnimationFrame(() => {
          node.style.scrollBehavior = 'smooth';
        });
      });
    }
  }, []); // 의존성 없음 - 마운트 시에만 실행

  // 로그 파일 목록 fetch 함수
  const fetchLogFiles = async () => {
    try {
      const token = localStorage.getItem('token');
      const params = new URLSearchParams();
      if (selectedLogServer !== 'all') params.append('serverId', selectedLogServer);
      if (selectedLogType !== 'all') params.append('fileType', selectedLogType);
      
      const response = await fetch(`/api/admin/logfiles?${params}`, {
        headers: { 'Authorization': `Bearer ${token}` }
      });
      const data = await response.json();
      if (data.files) {
        setLogFiles(data.files);
      }
      if (data.servers) {
        setLogServers(data.servers);
      }
    } catch (error) {
      console.error('로그 파일 목록 조회 실패:', error);
    }
  };

  // 로그 파일 목록 자동 fetch
  useEffect(() => {
    fetchLogFiles();
  }, [selectedLogServer, selectedLogType]);

  // 로그 파일 내용 보기
  const viewLogContent = async (file) => {
    setViewingLog(file);
    setLogViewerOpen(true);
    setLogLoading(true);
    setLogContent('');
    
    try {
      const token = localStorage.getItem('token');
      const response = await fetch(`/api/admin/logfile?id=${file.id}`, {
        headers: { 'Authorization': `Bearer ${token}` }
      });
      
      if (response.ok) {
        const blob = await response.blob();
        
        // .gz 파일만 압축 해제
        if (file.fileName.endsWith('.gz')) {
          const ds = new DecompressionStream('gzip');
          const decompressedStream = blob.stream().pipeThrough(ds);
          const decompressedBlob = await new Response(decompressedStream).blob();
          const text = await decompressedBlob.text();
          setLogContent(text);
        } else {
          // .log 파일은 직접 텍스트로 읽기
          const text = await blob.text();
          setLogContent(text);
        }
      } else {
        setLogContent('로그 파일을 불러올 수 없습니다.');
      }
    } catch (error) {
      console.error('로그 파일 로드 실패:', error);
      setLogContent('로그 파일을 불러오는 중 오류가 발생했습니다.');
    } finally {
      setLogLoading(false);
    }
  };

  // 로그 파일 삭제
  const deleteLogFile = async (file, e) => {
    if (e) e.stopPropagation();
    if (!confirm(`${file.fileName} 파일을 삭제하시겠습니까?`)) return;
    
    try {
      const token = localStorage.getItem('token');
      const response = await fetch(`/api/admin/logfile?id=${file.id}`, {
        method: 'DELETE',
        headers: { 'Authorization': `Bearer ${token}` }
      });
      
      if (response.ok) {
        fetchLogFiles(); // 목록 새로고침
      }
    } catch (error) {
      console.error('로그 파일 삭제 실패:', error);
    }
  };

  // 마인크래프트 색상 코드 매핑
  const MC_COLORS = {
    '0': '#000000', // Black
    '1': '#0000AA', // Dark Blue
    '2': '#00AA00', // Dark Green
    '3': '#00AAAA', // Dark Aqua
    '4': '#AA0000', // Dark Red
    '5': '#AA00AA', // Dark Purple
    '6': '#FFAA00', // Gold
    '7': '#AAAAAA', // Gray
    '8': '#555555', // Dark Gray
    '9': '#5555FF', // Blue
    'a': '#55FF55', // Green
    'b': '#55FFFF', // Aqua
    'c': '#FF5555', // Red
    'd': '#FF55FF', // Light Purple
    'e': '#FFFF55', // Yellow
    'f': '#FFFFFF', // White
  };

  // 마인크래프트 색상 코드를 HTML span으로 변환
  const parseMinecraftColors = (text) => {
    if (!text) return [];
    
    const parts = [];
    let currentColor = null;
    let buffer = '';
    let i = 0;
    
    while (i < text.length) {
      if (text[i] === '§' && i + 1 < text.length) {
        // 현재 버퍼 저장
        if (buffer) {
          parts.push({ text: buffer, color: currentColor });
          buffer = '';
        }
        
        const code = text[i + 1].toLowerCase();
        if (MC_COLORS[code]) {
          currentColor = MC_COLORS[code];
        } else if (code === 'r') {
          currentColor = '#FFFFFF'; // Reset to white
        }
        // k, l, m, n, o는 스타일 코드 (무시)
        i += 2;
      } else {
        buffer += text[i];
        i++;
      }
    }
    
    // 남은 버퍼 저장
    if (buffer) {
      parts.push({ text: buffer, color: currentColor });
    }
    
    return parts;
  };

  // 실제 서버 로그 Socket.io로 수신
  useEffect(() => {
    if (!isAdmin) return;

    // 초기 로그 fetch (Socket.io 연결 전)
    const fetchInitialLogs = async () => {
      try {
        const token = localStorage.getItem('token');
        const response = await fetch('/api/admin/logs', {
          headers: { 'Authorization': `Bearer ${token}` }
        });
        const data = await response.json();
        if (data.logs && data.logs.length > 0) {
          setLogs(data.logs.map(log => ({
            time: log.time,
            type: log.level === 'ERROR' ? 'error' : log.level === 'WARN' ? 'warning' : 'info',
            message: log.message
          })));
        }
      } catch (error) {
        console.error('초기 로그 조회 오류:', error);
      }
    };
    fetchInitialLogs();

    const socket = io('/', {
      path: '/socket.io',
      transports: ['websocket', 'polling']
    });

    socket.on('logs', (serverLogs) => {
      if (serverLogs && Array.isArray(serverLogs)) {
        setLogs(serverLogs.map(log => ({
          time: log.time,
          type: log.level === 'ERROR' ? 'error' : log.level === 'WARN' ? 'warning' : 'info',
          message: log.message
        })));
      }
    });
    
    // 플레이어 목록 실시간 업데이트
    socket.on('players', (playersList) => {
      if (playersList && Array.isArray(playersList)) {
        setPlayers(playersList);
      }
    });
    
    // 서버 상태에서 게임 규칙 가져오기
    socket.on('status', (status) => {
      if (status?.gameRules) {
        setGameRules(status.gameRules);
      }
      if (status?.difficulty) {
        // 난이도를 영문 ID로 변환
        const difficultyMap = {
          '평화로움': 'peaceful',
          '쉬움': 'easy',
          '보통': 'normal',
          '어려움': 'hard'
        };
        setDifficulty(difficultyMap[status.difficulty] || 'normal');
      }
    });
    
    // 월드 정보에서 시간/날씨 가져오기
    socket.on('worlds', (data) => {
      const worlds = data?.worlds || data;
      // 오버월드 찾기
      const overworld = worlds?.find(w => w.dimension === 'minecraft:overworld');
      if (overworld) {
        // 날씨 설정 (thunderstorm -> thunder로 변환)
        if (overworld.weather?.type) {
          const weatherMap = {
            'clear': 'clear',
            'rain': 'rain',
            'thunderstorm': 'thunder'
          };
          setWeather(weatherMap[overworld.weather.type] || 'clear');
        }
        
        // 시간 설정 (틱 기반으로 대략적인 시간대 결정)
        if (overworld.time?.dayTime !== undefined) {
          const dayTime = overworld.time.dayTime;
          // 0-6000: 아침/낮, 6000-12000: 낮/오후, 12000-24000: 밤
          if (dayTime >= 0 && dayTime < 6000) {
            setTimeOfDay('day');
          } else if (dayTime >= 6000 && dayTime < 12000) {
            setTimeOfDay('noon');
          } else {
            setTimeOfDay('night');
          }
        }
      }
    });
    
    // 월드 정보 요청
    socket.emit('get_worlds');

    return () => {
      socket.disconnect();
    };
  }, [isAdmin]);

  // 게임 규칙 설명 데이터 로드
  useEffect(() => {
    fetch('/api/gamerules')
      .then(res => res.json())
      .then(data => setGameRuleDescriptions(data))
      .catch(err => console.error('게임 규칙 설명 로드 실패:', err));
  }, []);

  // 명령어 실행 (실제 API 호출)
  const handleCommand = async () => {
    if (!command.trim()) return;
    
    try {
      const token = localStorage.getItem('token');
      await fetch('/api/admin/command', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`
        },
        body: JSON.stringify({ command: command.trim() })
      });
    } catch (error) {
      // 오류 무시 (로그에서 확인 가능)
    }
    
    setCommand('');
  };

  // 플레이어 액션 핸들러
  const handlePlayerAction = async () => {
    if (!selectedPlayer || !dialogAction) return;
    
    const token = localStorage.getItem('token');
    let command = '';
    let message = '';
    
    switch (dialogAction) {
      case 'kick':
        command = actionReason ? `kick ${selectedPlayer.name} ${actionReason}` : `kick ${selectedPlayer.name}`;
        message = `${selectedPlayer.displayName || selectedPlayer.name}님을 추방했습니다.`;
        break;
      case 'ban':
        command = actionReason ? `ban ${selectedPlayer.name} ${actionReason}` : `ban ${selectedPlayer.name}`;
        message = `${selectedPlayer.displayName || selectedPlayer.name}님을 차단했습니다.`;
        break;
      case 'unban':
        command = `pardon ${selectedPlayer.name}`;
        message = `${selectedPlayer.displayName || selectedPlayer.name}님의 차단을 해제했습니다.`;
        break;
      case 'op':
        const isOp = selectedPlayer.isOp;
        command = isOp ? `deop ${selectedPlayer.name}` : `op ${selectedPlayer.name}`;
        message = isOp ? `${selectedPlayer.displayName || selectedPlayer.name}님의 OP를 해제했습니다.` : `${selectedPlayer.displayName || selectedPlayer.name}님에게 OP를 부여했습니다.`;
        break;
    }
    
    try {
      const response = await fetch('/api/admin/command', {
        method: 'POST',
        headers: { 
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ command })
      });
      
      if (response.ok) {
        setToast(message);
        // 데이터 새로고침
        setTimeout(() => {
          fetchPlayers();
          fetchBanList();
        }, 500);
      } else {
        setToast('명령어 실행에 실패했습니다.');
      }
    } catch (error) {
      console.error('플레이어 액션 오류:', error);
      setToast('서버 연결에 실패했습니다.');
    }
    
    setShowPlayerDialog(false);
    setSelectedPlayer(null);
    setDialogAction(null);
    setActionReason('');
  };

  // 게임규칙 토글 (서버에 gamerule 명령어 전송)
  const toggleGamerule = async (name) => {
    const currentValue = gameRules[name];
    const newValue = !currentValue;
    
    // 낙관적 UI 업데이트
    setGameRules(prev => ({ ...prev, [name]: newValue }));
    
    try {
      const token = localStorage.getItem('token');
      await fetch('/api/admin/command', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`
        },
        body: JSON.stringify({ command: `gamerule ${name} ${newValue}` })
      });
      setToast(`${name}: ${newValue ? 'true' : 'false'}`);
    } catch (error) {
      // 실패 시 롤백
      setGameRules(prev => ({ ...prev, [name]: currentValue }));
      setToast('게임규칙 변경 실패');
    }
  };

  // 로그 색상 (hex 값 반환)
  const getLogColorHex = (type) => {
    switch (type) {
      case 'error': return '#f87171';   // red-400
      case 'warning': return '#facc15'; // yellow-400
      case 'command': return '#22c55e'; // mc-green
      default: return '#d4d4d8';        // zinc-300
    }
  };

  // 로그 색상 (클래스명 반환 - 시간용)
  const getLogColor = (type) => {
    switch (type) {
      case 'error': return 'text-red-400';
      case 'warning': return 'text-yellow-400';
      case 'command': return 'text-mc-green';
      default: return 'text-zinc-300';
    }
  };

  // 필터된 플레이어 (banned 필터는 banList 사용)
  const filteredPlayers = playerFilter === 'banned' 
    ? banList.map(ban => ({ 
        name: ban.name, 
        uuid: ban.uuid, 
        displayName: ban.name,
        isOnline: false, 
        isOp: false, 
        isBanned: true,
        banReason: ban.reason,
        banSource: ban.source
      }))
    : players.filter(p => {
        if (playerFilter === 'online') return p.isOnline;
        if (playerFilter === 'offline') return !p.isOnline;
        return true;
      });

  if (loading) {
    return (
      <div className="flex items-center justify-center min-h-[60vh]">
        <Loader2 className="w-8 h-8 text-mc-green animate-spin" />
      </div>
    );
  }

  if (!isLoggedIn || !isAdmin) {
    return (
      <>
        <AnimatePresence>
          {toast && (
            <motion.div
              initial={{ opacity: 0, y: 50 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: 50 }}
              className="fixed bottom-8 left-1/2 -translate-x-1/2 z-[200] bg-red-500/90 backdrop-blur-sm text-white px-6 py-3 rounded-xl text-center font-medium shadow-lg"
            >
              {toast}
            </motion.div>
          )}
        </AnimatePresence>
        <div className="flex items-center justify-center min-h-[60vh]">
          <Loader2 className="w-8 h-8 text-mc-green animate-spin" />
        </div>
      </>
    );
  }

  // 탭 설정
  const tabs = [
    { id: 'console', label: '콘솔', icon: Terminal },
    { id: 'players', label: '플레이어', icon: Users },
    { id: 'settings', label: '설정', icon: Settings },
  ];

  return (
    <div className="pb-8">
      {/* 토스트 */}
      <AnimatePresence>
        {toast && (
          <motion.div
            initial={{ opacity: 0, y: 50 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: 50 }}
            className="fixed bottom-8 left-1/2 -translate-x-1/2 z-[200] bg-mc-green/90 backdrop-blur-sm text-white px-6 py-3 rounded-xl text-center font-medium shadow-lg"
          >
            {toast}
          </motion.div>
        )}
      </AnimatePresence>

      {/* 모바일용 헤더 */}
      {isMobile && (
        <header className="bg-mc-dark border-b border-white/10 sticky top-0 z-50 backdrop-blur-xl">
          <div className="flex items-center h-14 px-4">
            <Link to="/" className="p-2 -ml-2 rounded-lg text-zinc-400 hover:text-white hover:bg-white/5 transition-colors">
              <ArrowLeft size={20} />
            </Link>
            <div className="ml-2">
              <h1 className="text-lg font-bold text-white">관리자</h1>
            </div>
          </div>
        </header>
      )}

      <main className={`max-w-4xl mx-auto px-4 sm:px-6 ${isMobile ? 'py-4' : 'py-8'}`}>
        {/* 데스크탑용 타이틀 */}
        {!isMobile && (
          <div className="mb-6">
            <h1 className="text-2xl font-bold text-white">관리자 페이지</h1>
            <p className="text-sm text-zinc-500 mt-1">서버 관리 및 설정</p>
          </div>
        )}

        {/* 탭 네비게이션 */}
        <div className="flex gap-1 p-1 bg-zinc-900 rounded-xl mb-6">
          {tabs.map(tab => (
            <button
              key={tab.id}
              onClick={() => setActiveTab(tab.id)}
              className={`flex-1 flex items-center justify-center gap-2 py-3 px-4 rounded-lg font-medium transition-all ${
                activeTab === tab.id
                  ? 'bg-zinc-800 text-white'
                  : 'text-zinc-400 hover:text-white hover:bg-zinc-800/50'
              }`}
            >
              <tab.icon size={18} />
              <span className={isMobile ? 'hidden sm:inline' : ''}>{tab.label}</span>
            </button>
          ))}
        </div>

        {/* 탭 콘텐츠 */}
        <AnimatePresence mode="wait">
          {/* 콘솔 탭 */}
          {activeTab === 'console' && (
            <motion.div
              key="console"
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -10 }}
              className="space-y-4"
            >
              {/* 로그 영역 */}
              <div className="bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden relative">
                <div 
                  ref={setLogContainerRef} 
                  onScroll={handleLogScroll}
                  className="h-[500px] overflow-y-auto p-4 font-mono text-sm custom-scrollbar" 
                  style={{ backgroundColor: '#181818', scrollBehavior: 'smooth' }}
                >
                  {logs.map((log, index) => (
                    <div 
                      key={index} 
                      className="leading-relaxed py-1 pl-3 mb-1"
                      style={{ borderLeft: `3px solid ${getLogColorHex(log.type)}` }}
                    >
                      <span className={getLogColor(log.type)}>[{log.time}]</span>{' '}
                      {parseMinecraftColors(log.message).map((part, i) => (
                        <span key={i} style={{ color: part.color || getLogColorHex(log.type) }}>
                          {part.text}
                        </span>
                      ))}
                    </div>
                  ))}
                  <div ref={logEndRef} />
                </div>
                
                {/* 맨 아래로 스크롤 버튼 */}
                <AnimatePresence>
                  {!isAtBottom && logs.length > 0 && (
                    <motion.button
                      initial={{ opacity: 0, scale: 0.8 }}
                      animate={{ opacity: 1, scale: 1 }}
                      exit={{ opacity: 0, scale: 0.8 }}
                      onClick={scrollToBottom}
                      className="absolute bottom-[88px] right-4 p-3 bg-mc-green hover:bg-mc-green/80 text-white rounded-full shadow-xl shadow-black/50 transition-colors z-10"
                      title="맨 아래로 이동"
                    >
                      <ArrowDown size={20} />
                    </motion.button>
                  )}
                </AnimatePresence>
                
                {/* 명령어 입력 */}
                <div className="p-4 border-t border-zinc-800">
                  <div className="flex gap-2">
                    <div className="flex-1 flex items-center bg-zinc-800 rounded-lg px-3">
                      <span className="text-mc-green mr-2">{'>'}</span>
                      <input
                        type="text"
                        value={command}
                        onChange={(e) => {
                          setCommand(e.target.value);
                          setHistoryIndex(-1);
                        }}
                        onKeyDown={(e) => {
                          // 히스토리 네비게이션
                          if (e.key === 'ArrowUp' && commandHistory.length > 0) {
                            e.preventDefault();
                            const newIndex = historyIndex < commandHistory.length - 1 ? historyIndex + 1 : historyIndex;
                            setHistoryIndex(newIndex);
                            setCommand(commandHistory[commandHistory.length - 1 - newIndex] || '');
                            return;
                          }
                          if (e.key === 'ArrowDown') {
                            e.preventDefault();
                            const newIndex = historyIndex > 0 ? historyIndex - 1 : -1;
                            setHistoryIndex(newIndex);
                            setCommand(newIndex >= 0 ? commandHistory[commandHistory.length - 1 - newIndex] : '');
                            return;
                          }
                          
                          // Enter 키로 명령어 실행
                          if (e.key === 'Enter' && command.trim()) {
                            // 히스토리에 추가
                            setCommandHistory(prev => [...prev.slice(-49), command]);
                            setHistoryIndex(-1);
                            handleCommand();
                          }
                        }}
                        placeholder="명령어 입력..."
                        className="flex-1 bg-transparent py-3 text-white placeholder-zinc-500 focus:outline-none font-mono"
                      />
                    </div>
                    <button
                      onClick={() => {
                        if (command.trim()) {
                          setCommandHistory(prev => [...prev.slice(-49), command]);
                          setHistoryIndex(-1);
                          handleCommand();
                        }
                      }}
                      disabled={!command.trim()}
                      className="px-4 py-3 bg-mc-green hover:bg-mc-green/80 disabled:bg-zinc-700 disabled:text-zinc-500 text-white rounded-lg transition-colors"
                    >
                      <Send size={18} />
                    </button>
                  </div>
                </div>
              </div>

              {/* 로그 파일 목록 */}
              <div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-4">
                <div className="flex items-center justify-between mb-3">
                  <h3 className="text-white font-medium flex items-center gap-2">
                    <FileText size={18} className="text-zinc-400" />
                    로그 파일
                    {logFiles.length > 0 && <span className="text-xs text-zinc-500">({logFiles.length})</span>}
                  </h3>
                  <button
                    onClick={fetchLogFiles}
                    className="p-2 text-zinc-400 hover:text-mc-green hover:bg-zinc-800 rounded-lg transition-all hover:rotate-180 duration-300"
                    title="새로고침"
                  >
                    <RefreshCw size={16} />
                  </button>
                </div>
                
                {/* 필터 드롭다운 */}
                <div className="flex gap-2 mb-3">
                  {/* 서버 선택 드롭다운 */}
                  <div className="relative">
                    <button
                      onClick={() => { setServerDropdownOpen(!serverDropdownOpen); setTypeDropdownOpen(false); }}
                      className="flex items-center gap-2 bg-zinc-800/80 text-zinc-300 text-xs px-3 py-2 rounded-lg border border-zinc-700/50 hover:bg-zinc-700/80 transition-colors"
                    >
                      <span>{selectedLogServer === 'all' ? '모든 서버' : selectedLogServer}</span>
                      <ChevronDown size={14} className={`text-zinc-500 transition-transform ${serverDropdownOpen ? 'rotate-180' : ''}`} />
                    </button>
                    {serverDropdownOpen && (
                      <div className="absolute top-full left-0 mt-1 bg-zinc-800 border border-zinc-700 rounded-lg shadow-xl z-10 min-w-[120px] py-1">
                        <button
                          onClick={() => { setSelectedLogServer('all'); setServerDropdownOpen(false); }}
                          className={`w-full text-left px-3 py-2 text-xs hover:bg-zinc-700 transition-colors ${selectedLogServer === 'all' ? 'text-mc-green' : 'text-zinc-300'}`}
                        >
                          모든 서버
                        </button>
                        {logServers.map(server => (
                          <button
                            key={server}
                            onClick={() => { setSelectedLogServer(server); setServerDropdownOpen(false); }}
                            className={`w-full text-left px-3 py-2 text-xs hover:bg-zinc-700 transition-colors ${selectedLogServer === server ? 'text-mc-green' : 'text-zinc-300'}`}
                          >
                            {server}
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                  
                  {/* 종류 선택 드롭다운 */}
                  <div className="relative">
                    <button
                      onClick={() => { setTypeDropdownOpen(!typeDropdownOpen); setServerDropdownOpen(false); }}
                      className="flex items-center gap-2 bg-zinc-800/80 text-zinc-300 text-xs px-3 py-2 rounded-lg border border-zinc-700/50 hover:bg-zinc-700/80 transition-colors"
                    >
                      <span>
                        {selectedLogType === 'all' ? '모든 종류' : 
                         selectedLogType === 'dated' ? '📅 날짜별' :
                         selectedLogType === 'debug' ? '🐛 디버그' : '⚡ 최신'}
                      </span>
                      <ChevronDown size={14} className={`text-zinc-500 transition-transform ${typeDropdownOpen ? 'rotate-180' : ''}`} />
                    </button>
                    {typeDropdownOpen && (
                      <div className="absolute top-full left-0 mt-1 bg-zinc-800 border border-zinc-700 rounded-lg shadow-xl z-10 min-w-[120px] py-1">
                        {[
                          { value: 'all', label: '모든 종류' },
                          { value: 'dated', label: '📅 날짜별' },
                          { value: 'debug', label: '🐛 디버그' },
                          { value: 'latest', label: '⚡ 최신' }
                        ].map(item => (
                          <button
                            key={item.value}
                            onClick={() => { setSelectedLogType(item.value); setTypeDropdownOpen(false); }}
                            className={`w-full text-left px-3 py-2 text-xs hover:bg-zinc-700 transition-colors ${selectedLogType === item.value ? 'text-mc-green' : 'text-zinc-300'}`}
                          >
                            {item.label}
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                </div>
                
                <div className="space-y-2 max-h-[300px] overflow-y-auto custom-scrollbar pr-2">
                  {logFiles.length === 0 ? (
                    <p className="text-zinc-500 text-sm text-center py-4">로그 파일이 없습니다</p>
                  ) : (
                    logFiles.map((file) => (
                      <div 
                        key={file.id} 
                        className="flex items-center justify-between p-3 bg-zinc-800/50 rounded-xl hover:bg-zinc-800 transition-colors cursor-pointer group"
                        onClick={() => viewLogContent(file)}
                      >
                        <div className="flex-1 min-w-0">
                          <p className="text-white text-sm truncate group-hover:text-mc-green transition-colors">{file.fileName}</p>
                          <p className="text-xs text-zinc-500">
                            {file.fileSize} • {file.serverId} • 
                            <span className={`ml-1 ${
                              file.fileType === 'debug' ? 'text-yellow-500' : 
                              file.fileType === 'latest' ? 'text-blue-400' : 'text-zinc-400'
                            }`}>
                              {file.fileType}
                            </span>
                          </p>
                        </div>
                        <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
                          <button 
                            onClick={(e) => deleteLogFile(file, e)}
                            className="p-2 text-zinc-400 hover:text-red-500 hover:bg-zinc-700 rounded-lg transition-colors"
                            title="삭제"
                          >
                            <Trash2 size={16} />
                          </button>
                          <button 
                            onClick={async (e) => {
                              e.stopPropagation();
                              const token = localStorage.getItem('token');
                              const response = await fetch(`/api/admin/logfile?id=${file.id}`, {
                                headers: { 'Authorization': `Bearer ${token}` }
                              });
                              if (response.ok) {
                                const blob = await response.blob();
                                const url = URL.createObjectURL(blob);
                                const a = document.createElement('a');
                                a.href = url;
                                a.download = file.fileName;
                                a.click();
                                URL.revokeObjectURL(url);
                              }
                            }}
                            className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-700 rounded-lg transition-colors"
                            title="다운로드"
                          >
                            <Download size={16} />
                          </button>
                        </div>
                      </div>
                    ))
                  )}
                </div>
              </div>
            </motion.div>
          )}

          {/* 플레이어 탭 */}
          {activeTab === 'players' && (
            <motion.div
              key="players"
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -10 }}
              className="space-y-4"
            >
              {/* 필터 */}
              <div className="flex gap-2">
                {[
                  { id: 'all', label: '전체' },
                  { id: 'online', label: '온라인' },
                  { id: 'offline', label: '오프라인' },
                  { id: 'banned', label: '차단됨' },
                ].map(filter => (
                  <button
                    key={filter.id}
                    onClick={() => setPlayerFilter(filter.id)}
                    className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
                      playerFilter === filter.id
                        ? filter.id === 'banned' ? 'bg-red-500 text-white' : 'bg-mc-green text-white'
                        : 'bg-zinc-800 text-zinc-400 hover:text-white'
                    }`}
                  >
                    {filter.label}
                    {filter.id === 'banned' && banList.length > 0 && (
                      <span className="ml-1 text-xs">({banList.length})</span>
                    )}
                  </button>
                ))}
              </div>

              {/* 플레이어 그리드 */}
              <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
                {filteredPlayers.map((player) => (
                  <div
                    key={player.uuid}
                    className="bg-zinc-900 border border-zinc-800 rounded-2xl p-4 text-center relative group"
                  >
                    {/* OP 뱃지 */}
                    {player.isOp && (
                      <div className="absolute top-2 right-2 bg-yellow-500 p-1 rounded-lg">
                        <Crown size={12} className="text-black" />
                      </div>
                    )}
                    
                    {/* 온/오프라인 표시 */}
                    <div className={`absolute top-2 left-2 w-3 h-3 rounded-full ${player.isOnline ? 'bg-green-500' : 'bg-zinc-600'}`} />
                    
                    {/* 전신 아바타 */}
                    <img
                      src={`https://mc-heads.net/body/${player.uuid}/100`}
                      alt={player.name}
                      className="w-16 h-32 mx-auto mb-2 drop-shadow-lg"
                    />
                    
                    <p className="text-white font-medium">{player.displayName || player.name}</p>
                    <p className="text-xs text-zinc-500">{player.name}</p>
                    {player.isBanned && (
                      <span className="text-xs text-red-400 block">차단됨</span>
                    )}
                    
                    {/* 액션 버튼 - mt-2 추가 */}
                    <div className="flex justify-center gap-1 mt-2">
                      <button
                        onClick={() => {
                          setSelectedPlayer(player);
                          setDialogAction('op');
                          setShowPlayerDialog(true);
                        }}
                        className={`p-2 rounded-lg transition-colors ${
                          player.isOp 
                            ? 'bg-yellow-500/20 text-yellow-500 hover:bg-yellow-500/30'
                            : 'bg-zinc-800 text-zinc-400 hover:text-yellow-500'
                        }`}
                        title="OP"
                      >
                        <Crown size={16} />
                      </button>
                      {player.isOnline && (
                        <button
                          onClick={() => {
                            setSelectedPlayer(player);
                            setDialogAction('kick');
                            setShowPlayerDialog(true);
                          }}
                          className="p-2 bg-zinc-800 text-zinc-400 hover:text-orange-500 rounded-lg transition-colors"
                          title="킥"
                        >
                          <UserX size={16} />
                        </button>
                      )}
                      {player.isBanned ? (
                        <button
                          onClick={() => {
                            setSelectedPlayer(player);
                            setDialogAction('unban');
                            setShowPlayerDialog(true);
                          }}
                          className="p-2 bg-green-500/20 text-green-500 hover:bg-green-500/30 rounded-lg transition-colors"
                          title="차단 해제"
                        >
                          <Check size={16} />
                        </button>
                      ) : (
                        <button
                          onClick={() => {
                            setSelectedPlayer(player);
                            setDialogAction('ban');
                            setShowPlayerDialog(true);
                          }}
                          className="p-2 bg-zinc-800 text-zinc-400 hover:text-red-500 rounded-lg transition-colors"
                          title="밴"
                        >
                          <Ban size={16} />
                        </button>
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </motion.div>
          )}

          {/* 설정 탭 */}
          {activeTab === 'settings' && (
            <motion.div
              key="settings"
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -10 }}
              className="space-y-4"
            >
              {/* 게임규칙 */}
              <div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-4">
                <h3 className="text-white font-medium mb-4 flex items-center gap-2">
                  🎮 게임규칙
                  <span className="text-sm font-normal text-zinc-500">
                    ({Object.keys(gameRules).length})
                  </span>
                </h3>
                {Object.keys(gameRules).length > 0 ? (
                  <div className="max-h-80 overflow-y-auto custom-scrollbar pr-2">
                    <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
                      {Object.entries(gameRules).map(([rule, value]) => (
                        <button
                          key={rule}
                          onClick={() => toggleGamerule(rule)}
                          className={`flex items-center justify-between p-3 rounded-xl transition-colors border ${
                            value ? 'bg-mc-green/20 border-mc-green/30' : 'bg-zinc-800/50 border-transparent hover:border-zinc-700'
                          }`}
                        >
                          <Tooltip 
                            content={gameRuleDescriptions[rule]?.description || gameRuleDescriptions[rule]?.name || "설명이 없습니다."} 
                            className="min-w-0 flex-1 mr-2 text-left"
                          >
                            <span className="text-white text-sm truncate block cursor-default hover:text-zinc-300 transition-colors">
                              {rule}
                            </span>
                          </Tooltip>
                          <div className={`w-10 h-6 rounded-full relative transition-colors shrink-0 ${value ? 'bg-mc-green' : 'bg-zinc-600'}`}>
                            <div className={`absolute top-1 w-4 h-4 rounded-full bg-white transition-transform ${value ? 'left-5' : 'left-1'}`} />
                          </div>
                        </button>
                      ))}
                    </div>
                  </div>
                ) : (
                  <div className="text-zinc-500 text-sm py-4 text-center">
                    게임 규칙을 불러오는 중...
                  </div>
                )}
              </div>

              {/* 난이도 */}
              <div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-4">
                <h3 className="text-white font-medium mb-4">⚔️ 난이도</h3>
                <div className="flex gap-2 flex-wrap">
                  {[
                    { id: 'peaceful', label: '평화로움' },
                    { id: 'easy', label: '쉬움' },
                    { id: 'normal', label: '보통' },
                    { id: 'hard', label: '어려움' },
                  ].map(d => (
                    <button
                      key={d.id}
                      onClick={async () => {
                        setDifficulty(d.id);
                        try {
                          const token = localStorage.getItem('token');
                          await fetch('/api/admin/command', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
                            body: JSON.stringify({ command: `difficulty ${d.id}` })
                          });
                          setToast(`난이도: ${d.label}`);
                        } catch (error) {
                          setToast('난이도 변경 실패');
                        }
                      }}
                      className={`flex-1 min-w-[80px] py-3 px-4 rounded-xl font-medium transition-colors ${
                        difficulty === d.id
                          ? 'bg-mc-green text-white'
                          : 'bg-zinc-800 text-zinc-400 hover:text-white'
                      }`}
                    >
                      {d.label}
                    </button>
                  ))}
                </div>
              </div>

              {/* 시간 */}
              <div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-4">
                <h3 className="text-white font-medium mb-4">🕐 시간</h3>
                <div className="flex gap-2 flex-wrap">
                  {[
                    { id: 'day', label: '아침', icon: Sun, time: '1000' },
                    { id: 'noon', label: '낮', icon: Sun, time: '6000' },
                    { id: 'night', label: '밤', icon: Moon, time: '13000' },
                  ].map(t => (
                    <button
                      key={t.id}
                      onClick={async () => {
                        setTimeOfDay(t.id);
                        try {
                          const token = localStorage.getItem('token');
                          await fetch('/api/admin/command', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
                            body: JSON.stringify({ command: `time set ${t.time}` })
                          });
                          setToast(`시간: ${t.label}`);
                        } catch (error) {
                          setToast('시간 변경 실패');
                        }
                      }}
                      className={`flex-1 flex items-center justify-center gap-2 py-3 px-4 rounded-xl font-medium transition-colors ${
                        timeOfDay === t.id
                          ? 'bg-blue-500 text-white'
                          : 'bg-zinc-800 text-zinc-400 hover:text-white'
                      }`}
                    >
                      <t.icon size={18} />
                      {t.label}
                    </button>
                  ))}
                </div>
              </div>

              {/* 날씨 */}
              <div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-4">
                <h3 className="text-white font-medium mb-4">🌤️ 날씨</h3>
                <div className="flex gap-2 flex-wrap">
                  {[
                    { id: 'clear', label: '맑음', icon: Sun },
                    { id: 'rain', label: '비', icon: CloudRain },
                    { id: 'thunder', label: '천둥', icon: CloudLightning },
                  ].map(w => (
                    <button
                      key={w.id}
                      onClick={async () => {
                        setWeather(w.id);
                        try {
                          const token = localStorage.getItem('token');
                          await fetch('/api/admin/command', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
                            body: JSON.stringify({ command: `weather ${w.id}` })
                          });
                          setToast(`날씨: ${w.label}`);
                        } catch (error) {
                          setToast('날씨 변경 실패');
                        }
                      }}
                      className={`flex-1 flex items-center justify-center gap-2 py-3 px-4 rounded-xl font-medium transition-colors ${
                        weather === w.id
                          ? 'bg-cyan-500 text-white'
                          : 'bg-zinc-800 text-zinc-400 hover:text-white'
                      }`}
                    >
                      <w.icon size={18} />
                      {w.label}
                    </button>
                  ))}
                </div>
              </div>
            </motion.div>
          )}
        </AnimatePresence>
      </main>

      {/* 플레이어 액션 다이얼로그 */}
      <AnimatePresence>
        {showPlayerDialog && selectedPlayer && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100] flex items-center justify-center p-4"
            onClick={() => setShowPlayerDialog(false)}
          >
            <motion.div
              initial={{ scale: 0.9, opacity: 0 }}
              animate={{ scale: 1, opacity: 1 }}
              exit={{ scale: 0.9, opacity: 0 }}
              className="bg-zinc-900 border border-zinc-700 rounded-2xl p-6 w-full max-w-md"
              onClick={(e) => e.stopPropagation()}
            >
              <h3 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
                {dialogAction === 'kick' && <><UserX size={20} className="text-orange-500" /> 플레이어 킥</>}
                {dialogAction === 'ban' && <><Ban size={20} className="text-red-500" /> 플레이어 밴</>}
                {dialogAction === 'unban' && <><Check size={20} className="text-green-500" /> 차단 해제</>}
                {dialogAction === 'op' && <><Crown size={20} className="text-yellow-500" /> OP {selectedPlayer?.isOp ? '해제' : '부여'}</>}
              </h3>
              
              <div className="flex items-center gap-4 mb-4">
                <img
                  src={`https://mc-heads.net/body/${selectedPlayer.uuid}/60`}
                  alt={selectedPlayer.name}
                  className="w-10 h-20"
                />
                <div>
                  <p className="text-white font-medium">{selectedPlayer.displayName || selectedPlayer.name}</p>
                  <p className="text-xs text-zinc-500">{selectedPlayer.uuid}</p>
                </div>
              </div>

              {(dialogAction === 'kick' || dialogAction === 'ban') && (
                <input
                  type="text"
                  value={actionReason}
                  onChange={(e) => setActionReason(e.target.value)}
                  placeholder="사유 (선택)"
                  className="w-full bg-zinc-800 rounded-xl p-3 text-white placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-mc-green/50 mb-4"
                />
              )}

              <div className="flex gap-2">
                <button
                  onClick={() => setShowPlayerDialog(false)}
                  className="flex-1 py-3 bg-zinc-800 hover:bg-zinc-700 text-white rounded-xl transition-colors"
                >
                  취소
                </button>
                <button
                  onClick={handlePlayerAction}
                  className={`flex-1 py-3 font-medium rounded-xl transition-colors ${
                    dialogAction === 'kick' ? 'bg-orange-500 hover:bg-orange-600 text-white' :
                    dialogAction === 'ban' ? 'bg-red-500 hover:bg-red-600 text-white' :
                    dialogAction === 'unban' ? 'bg-green-500 hover:bg-green-600 text-white' :
                    'bg-yellow-500 hover:bg-yellow-600 text-black'
                  }`}
                >
                  확인
                </button>
              </div>
            </motion.div>
          </motion.div>
        )}

        {/* 로그 뷰어 다이얼로그 */}
        {logViewerOpen && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 bg-black/80 backdrop-blur-sm flex items-center justify-center z-50 p-4"
            onClick={() => setLogViewerOpen(false)}
          >
            <motion.div
              initial={{ scale: 0.95, opacity: 0 }}
              animate={{ scale: 1, opacity: 1 }}
              exit={{ scale: 0.95, opacity: 0 }}
              className="bg-zinc-900 border border-zinc-800 rounded-2xl p-6 w-full max-w-4xl max-h-[80vh] flex flex-col"
              onClick={(e) => e.stopPropagation()}
            >
              {/* 헤더 */}
              <div className="flex items-center justify-between mb-4">
                <div className="flex items-center gap-3">
                  <FileText className="text-mc-green" size={24} />
                  <div>
                    <h3 className="text-white font-medium">{viewingLog?.fileName}</h3>
                    <p className="text-xs text-zinc-500">
                      {viewingLog?.fileSize} • {viewingLog?.serverId} • {viewingLog?.fileType}
                    </p>
                  </div>
                </div>
                <button
                  onClick={() => setLogViewerOpen(false)}
                  className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
                >
                  <X size={20} />
                </button>
              </div>
              
              {/* 로그 내용 */}
              <div className="flex-1 bg-black/50 rounded-xl p-4 overflow-auto custom-scrollbar font-mono text-xs pr-2" style={{ backgroundColor: '#181818' }}>
                {logLoading ? (
                  <div className="flex items-center justify-center h-full">
                    <Loader2 className="animate-spin text-mc-green" size={32} />
                  </div>
                ) : (
                  <div className="whitespace-pre-wrap break-words leading-5">
                    {logContent.split('\n').map((line, idx) => {
                      // 로그 레벨 추출 (INFO, WARN, ERROR)
                      const logType = line.includes('/ERROR]') || line.includes('[ERROR]') ? 'error' :
                                      line.includes('/WARN]') || line.includes('[WARN]') ? 'warning' : 'info';
                      const colorHex = logType === 'error' ? '#f87171' : 
                                       logType === 'warning' ? '#facc15' : '#d4d4d8';
                      
                      return (
                        <div 
                          key={idx}
                          className="py-1 pl-3 mb-1"
                          style={{ borderLeft: `3px solid ${colorHex}` }}
                        >
                          {parseMinecraftColors(line).map((part, pIdx) => (
                            <span key={pIdx} style={{ color: part.color || colorHex }}>{part.text}</span>
                          ))}
                        </div>
                      );
                    })}
                  </div>
                )}
              </div>
              
              {/* 하단 버튼 */}
              <div className="flex justify-end gap-2 mt-4">
                <button
                  onClick={async () => {
                    if (!viewingLog) return;
                    const token = localStorage.getItem('token');
                    const response = await fetch(`/api/admin/logfile?id=${viewingLog.id}`, {
                      headers: { 'Authorization': `Bearer ${token}` }
                    });
                    if (response.ok) {
                      const blob = await response.blob();
                      const url = URL.createObjectURL(blob);
                      const a = document.createElement('a');
                      a.href = url;
                      a.download = viewingLog.fileName;
                      a.click();
                      URL.revokeObjectURL(url);
                    }
                  }}
                  className="flex items-center gap-2 px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-white rounded-lg transition-colors"
                >
                  <Download size={16} />
                  다운로드
                </button>
                <button
                  onClick={() => setLogViewerOpen(false)}
                  className="px-4 py-2 bg-mc-green hover:bg-mc-green-dark text-white rounded-lg transition-colors"
                >
                  닫기
                </button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}
