import React, { useState, useEffect, useRef } from 'react';
import { useParams } from 'react-router-dom';
import { Activity, Skull, Heart, LocateFixed, Box, Sword, Clock, Calendar, RefreshCw } from 'lucide-react';
import { motion } from 'framer-motion';
import { io } from 'socket.io-client';
import { formatDate, formatPlayTimeMs } from '../utils/formatters';


// 스티브 3D 스킨 기본 이미지 (로딩 전/실패 시 사용)
const STEVE_BODY_BASE64 = 'data:image/png;base64,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';

// 플레이어 3D 스킨 컴포넌트 - 스킨 캐싱 API 사용
const PlayerSkinImage = ({ uuid, playerName }) => {
  const [src, setSrc] = useState(STEVE_BODY_BASE64);
  
  useEffect(() => {
    // 스킨 캐싱 API 호출 (body/uuid/size)
    fetch(`/link/skin/body/${uuid}/80`)
      .then(res => res.json())
      .then(data => {
        if (data.url) {
          const img = new Image();
          img.onload = () => setSrc(data.url);
          img.onerror = () => setSrc(`https://mc-heads.net/body/${uuid}/80`);
          img.src = data.url;
        }
      })
      .catch(() => {
        // 폴백: mc-heads 직접 사용
        setSrc(`https://mc-heads.net/body/${uuid}/80`);
      });
  }, [uuid]);
  
  return (
    <img 
      src={src}
      alt={playerName}
      className="h-20 w-auto"
    />
  );
};

// 아이템/몹 아이콘 기본 이미지 (로딩 실패 시 사용)
const DEFAULT_ICON = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABhSURBVFhH7c4xDQAgDATAH/+fxsaCj8FqJndzCSFJkiRJkvRnvW+v+wGAzwfgM/4MAH7HD/Bh/BkA/Iof4MP4fgDwd/wZAPwaP8CH8f0A4O/4MwD4NT6AD+MbAPr9ALgBj+YLdQAAAABJRU5ErkJggg==';

// 거리 포맷 함수 - 1만 이상이면 "1.2만m" 형식으로 표시
const formatDistance = (meters) => {
  if (meters >= 100000000) {
    // 1억 이상
    return `${(meters / 100000000).toFixed(1)}억m`;
  } else if (meters >= 10000000) {
    // 천만 이상
    return `${(meters / 10000000).toFixed(1)}천만m`;
  } else if (meters >= 10000) {
    // 만 이상
    return `${(meters / 10000).toFixed(1)}만m`;
  }
  return `${meters.toLocaleString()}m`;
};

// 플레이어 통계 페이지
const PlayerStatsPage = ({ isMobile = false }) => {
  const { uuid } = useParams();
  const [playerName, setPlayerName] = useState('');
  const [playerDetail, setPlayerDetail] = useState(null);
  const [stats, setStats] = useState(null);
  const [translations, setTranslations] = useState({});
  const [icons, setIcons] = useState({});  // 아이콘 캐시
  const [loading, setLoading] = useState(true);
  const socketRef = useRef(null);

  // 번역 및 아이콘 데이터 로드
  useEffect(() => {
    Promise.all([
      fetch('/api/translations').then(res => res.json()),
      fetch('/api/icons').then(res => res.json())
    ])
      .then(([transData, iconsData]) => {
        setTranslations(transData);
        setIcons(iconsData);
      })
      .catch(err => console.error('데이터 로드 실패:', err));
  }, []);

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

    socket.on('player_stats', (data) => {
      setStats(data);
      setLoading(false);
    });

    socket.on('player_detail', (data) => {
      if (data) {
        setPlayerName(data.name);
        setPlayerDetail(data);
      }
    });

    socket.emit('get_player', uuid);
    socket.emit('get_player_stats', uuid);

    const interval = setInterval(() => {
      socket.emit('get_player', uuid);
      socket.emit('get_player_stats', uuid);
    }, 1000);

    return () => {
      clearInterval(interval);
      socket.disconnect();
    };
  }, [uuid]);



  const firstPlayed = formatDate(playerDetail?.firstJoin);
  const lastPlayed = formatDate(playerDetail?.lastLeave > 0 ? playerDetail?.lastLeave : playerDetail?.lastJoin);

  // 번역 함수 (DB에 없으면 영어 그대로)
  const translate = (id) => translations[id] || id.replace(/_/g, ' ');

  // 아이템 통계 정렬 (이름순)
  const sortedItems = stats?.items 
    ? Object.entries(stats.items)
        .map(([id, stat]) => ({
          id,
          ...stat,
          total: (stat.mined || 0) + (stat.used || 0) + (stat.pickedUp || 0) + (stat.crafted || 0)
        }))
        .sort((a, b) => translate(a.id).localeCompare(translate(b.id), 'ko'))
    : [];
    
  // 몹 통계 정렬 (이름순)
  const sortedMobs = stats?.mobs
    ? Object.entries(stats.mobs)
        .map(([id, stat]) => ({
          id,
          ...stat,
          total: (stat.killed || 0) + (stat.killedBy || 0)
        }))
        .sort((a, b) => translate(a.id).localeCompare(translate(b.id), 'ko'))
    : [];

  return (
    <div className="min-h-screen p-4 md:p-6 lg:p-8">
      <div className="max-w-5xl mx-auto">
        {/* 헤더 */}
        <div className="mb-8">
          <div className="flex items-center gap-4">
            <PlayerSkinImage uuid={uuid} playerName={playerName} />
            <div>
              <h1 className="text-3xl md:text-4xl font-bold text-white">{playerName || '로딩중...'}</h1>
              <p className="text-gray-400">플레이어 통계</p>
            </div>
          </div>
        </div>

        {loading ? (
          <div className="flex items-center justify-center py-20">
            <div className="w-12 h-12 border-4 border-mc-green/30 border-t-mc-green rounded-full animate-spin" />
          </div>
        ) : !stats ? (
          <div className="text-center py-20 text-gray-400">
            <Activity size={48} className="mx-auto mb-4 opacity-50" />
            <p>통계를 불러올 수 없습니다. 플레이어가 접속 중이어야 합니다.</p>
          </div>
        ) : (
          <div className="space-y-6">
            {/* 플레이어 정보 */}
            {playerDetail && (
              <motion.section
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.1, duration: 0.3 }}
              >
                <h2 className="text-xl font-bold text-white mb-4 flex items-center gap-2">
                  <Clock className="text-mc-diamond" />
                  플레이어 정보
                </h2>
                
                <div className={`grid gap-4 ${isMobile ? 'grid-cols-1' : 'grid-cols-4'}`}>
                  {/* 현재 세션 플레이타임 (접속 중일 때만) */}
                  {playerDetail.isOnline && (
                    <div className="glow-card rounded-xl p-5 border border-mc-green/30">
                      <div className="text-gray-400 text-xs md:text-sm mb-2 font-medium flex items-center gap-2">
                        <div className="p-1.5 rounded-md bg-mc-green/10">
                          <Clock size={14} className="text-mc-green icon-glow" />
                        </div>
                        현재 세션 플레이타임
                      </div>
                      <div className="text-white font-bold text-2xl md:text-3xl text-gradient">
                        {formatPlayTimeMs(playerDetail.currentSessionMs)}
                      </div>
                    </div>
                  )}

                  {/* 누적 플레이타임 */}
                  <div className="glow-card rounded-xl p-5">
                    <div className="text-gray-400 text-xs md:text-sm mb-2 font-medium flex items-center gap-2">
                      <div className="p-1.5 rounded-md bg-mc-emerald/10">
                        <Activity size={14} className="text-mc-emerald" />
                      </div>
                      누적 플레이타임
                    </div>
                    <div className="text-white font-bold text-2xl md:text-3xl">
                      {formatPlayTimeMs(playerDetail.totalPlayTimeMs + (playerDetail.isOnline ? playerDetail.currentSessionMs : 0))}
                    </div>
                  </div>
                  
                  {/* 첫 접속 */}
                  <div className="glow-card rounded-xl p-5">
                    <div className="text-gray-400 text-xs md:text-sm mb-2 font-medium flex items-center gap-2">
                      <div className="p-1.5 rounded-md bg-mc-diamond/10">
                        <Calendar size={14} className="text-mc-diamond" />
                      </div>
                      첫 접속
                    </div>
                    <div className="text-white font-bold text-base md:text-lg">
                      <div>{firstPlayed.date}</div>
                      <div className="text-gray-400 text-sm md:text-base font-normal">{firstPlayed.time}</div>
                    </div>
                  </div>
                  
                  {/* 마지막 접속 */}
                  <div className="glow-card rounded-xl p-5">
                    <div className="text-gray-400 text-xs md:text-sm mb-2 font-medium flex items-center gap-2">
                      <div className="p-1.5 rounded-md bg-mc-emerald/10">
                        <RefreshCw size={14} className="text-mc-emerald" />
                      </div>
                      마지막 접속
                    </div>
                    <div className="text-white font-bold text-base md:text-lg">
                      <div>{lastPlayed.date}</div>
                      <div className="text-gray-400 text-sm md:text-base font-normal">{lastPlayed.time}</div>
                    </div>
                  </div>
                </div>
              </motion.section>
            )}

            {/* 일반 통계 */}
            <motion.section
              initial={{ opacity: 0, y: 20 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ delay: 0.2, duration: 0.3 }}
            >
              <h2 className="text-xl font-bold text-white mb-4 flex items-center gap-2">
                <Activity className="text-mc-green" />
                일반 통계
              </h2>
              <div className="grid grid-cols-2 md:grid-cols-5 gap-3">
                <StatCard icon={Skull} label="사망 횟수" value={stats.general.deaths} color="text-red-400" />
                <StatCard icon={Sword} label="몹 처치" value={stats.general.mobKills} color="text-orange-400" />
                <StatCard icon={Sword} label="입힌 피해" value={stats.general.damageDealt} color="text-yellow-400" />
                <StatCard icon={Heart} label="받은 피해" value={stats.general.damageTaken} color="text-pink-400" />
                <StatCard icon={LocateFixed} label="점프 횟수" value={stats.general.jumps} color="text-blue-400" />
              </div>
            </motion.section>

            {/* 이동 거리 */}
            <motion.section
              initial={{ opacity: 0, y: 20 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ delay: 0.3, duration: 0.3 }}
            >
              <h2 className="text-xl font-bold text-white mb-4 flex items-center gap-2">
                <LocateFixed className="text-blue-400" />
                이동 거리
              </h2>
              <div className="grid grid-cols-3 gap-3">
                <div className="glow-card rounded-xl p-4 flex flex-col items-center justify-center">
                  <p className="text-gray-400 text-sm mb-1">걸은 거리</p>
                  <p className={`font-bold text-white ${isMobile ? 'text-lg' : 'text-2xl'}`}>
                    {isMobile ? formatDistance(stats.general.distanceWalked) : `${stats.general.distanceWalked.toLocaleString()}m`}
                  </p>
                </div>
                <div className="glow-card rounded-xl p-4 flex flex-col items-center justify-center">
                  <p className="text-gray-400 text-sm mb-1">비행 거리</p>
                  <p className={`font-bold text-white ${isMobile ? 'text-lg' : 'text-2xl'}`}>
                    {isMobile ? formatDistance(stats.general.distanceFlown) : `${stats.general.distanceFlown.toLocaleString()}m`}
                  </p>
                </div>
                <div className="glow-card rounded-xl p-4 flex flex-col items-center justify-center">
                  <p className="text-gray-400 text-sm mb-1">수영 거리</p>
                  <p className={`font-bold text-white ${isMobile ? 'text-lg' : 'text-2xl'}`}>
                    {isMobile ? formatDistance(stats.general.distanceSwum) : `${stats.general.distanceSwum.toLocaleString()}m`}
                  </p>
                </div>
              </div>
            </motion.section>

            {/* 아이템 통계 - 4열 그리드 + 내부 스크롤 */}
            {sortedItems.length > 0 && (
              <motion.section
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.4, duration: 0.3 }}
              >
                <h2 className="text-xl font-bold text-white mb-4 flex items-center gap-2">
                  <Box className="text-yellow-400" />
                  아이템 통계
                  <span className="text-gray-500 text-sm font-normal">({sortedItems.length}개)</span>
                </h2>
                <div className="glow-card rounded-xl overflow-hidden">
                  <div className="max-h-[400px] overflow-y-auto custom-scrollbar">
                    <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
                      {sortedItems.map((item) => (
                        <ItemStatRow key={item.id} item={item} translate={translate} icons={icons} />
                      ))}
                    </div>
                  </div>
                </div>
              </motion.section>
            )}

            {/* 몹 통계 - 4열 그리드 + 내부 스크롤 */}
            {sortedMobs.length > 0 && (
              <motion.section
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.5, duration: 0.3 }}
              >
                <h2 className="text-xl font-bold text-white mb-4 flex items-center gap-2">
                  <Sword className="text-red-400" />
                  몹 통계
                  <span className="text-gray-500 text-sm font-normal">({sortedMobs.length}마리)</span>
                </h2>
                <div className="glow-card rounded-xl overflow-hidden">
                  <div className="max-h-[400px] overflow-y-auto custom-scrollbar">
                    <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
                      {sortedMobs.map((mob) => (
                        <MobStatRow key={mob.id} mob={mob} translate={translate} icons={icons} />
                      ))}
                    </div>
                  </div>
                </div>
              </motion.section>
            )}

            {sortedItems.length === 0 && sortedMobs.length === 0 && (
              <div className="text-center py-10 text-gray-500">
                <p>아직 기록된 통계가 없습니다.</p>
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
};

// 통계 카드 컴포넌트
const StatCard = ({ icon: Icon, label, value, color }) => (
  <div className="glow-card rounded-xl p-4 flex items-center gap-3 transition-colors hover:bg-white/5">
    <div className={`p-2 rounded-lg bg-white/5 ${color}`}>
      <Icon size={20} />
    </div>
    <div>
      <p className="text-gray-400 text-xs">{label}</p>
      <p className="text-lg font-bold text-white">{typeof value === 'number' ? value.toLocaleString() : value}</p>
    </div>
  </div>
);

// 아이템 통계 행 컴포넌트 (온디맨드 아이콘 지원)
const ItemStatRow = ({ item, translate, icons }) => {
  const [iconSrc, setIconSrc] = useState(icons[item.id] || DEFAULT_ICON);
  const [loading, setLoading] = useState(!icons[item.id]);

  // 아이콘이 없으면 온디맨드로 가져오기
  useEffect(() => {
    if (!icons[item.id]) {
      fetch(`/api/icon/item/${item.id}`)
        .then(res => res.json())
        .then(data => {
          if (data.icon) {
            setIconSrc(data.icon);
          }
        })
        .catch(() => {})
        .finally(() => setLoading(false));
    }
  }, [item.id, icons]);
  
  return (
    <div className="p-3 flex items-center gap-3 hover:bg-white/5 transition-colors border-b border-r border-white/5">
      <img 
        src={iconSrc}
        alt={item.id}
        className="w-8 h-8 object-contain pixelated"
        onError={(e) => { e.target.src = DEFAULT_ICON; }}
      />
      <div className="flex-1 min-w-0">
        <p className="text-white text-sm font-medium truncate" title={translate(item.id)}>
          {translate(item.id)}
        </p>
        <div className="flex flex-wrap gap-x-2 text-xs text-gray-400">
          {item.mined > 0 && <span>채굴 <span className="text-yellow-400">{item.mined}</span></span>}
          {item.used > 0 && <span>사용 <span className="text-blue-400">{item.used}</span></span>}
          {item.pickedUp > 0 && <span>획득 <span className="text-green-400">{item.pickedUp}</span></span>}
          {item.crafted > 0 && <span>제작 <span className="text-purple-400">{item.crafted}</span></span>}
        </div>
      </div>
    </div>
  );
};

// 몹 통계 행 컴포넌트 (온디맨드 아이콘 지원)
const MobStatRow = ({ mob, translate, icons }) => {
  const [iconSrc, setIconSrc] = useState(icons[mob.id] || DEFAULT_ICON);
  const [loading, setLoading] = useState(!icons[mob.id]);

  // 아이콘이 없으면 온디맨드로 가져오기
  useEffect(() => {
    if (!icons[mob.id]) {
      fetch(`/api/icon/entity/${mob.id}`)
        .then(res => res.json())
        .then(data => {
          if (data.icon) {
            setIconSrc(data.icon);
          }
        })
        .catch(() => {})
        .finally(() => setLoading(false));
    }
  }, [mob.id, icons]);
  
  return (
    <div className="p-3 flex items-center gap-3 hover:bg-white/5 transition-colors border-b border-r border-white/5">
      <img 
        src={iconSrc}
        alt={mob.id}
        className="w-8 h-8 object-contain pixelated"
        onError={(e) => { e.target.src = DEFAULT_ICON; }}
      />
      <div className="flex-1 min-w-0">
        <p className="text-white text-sm font-medium truncate" title={translate(mob.id)}>
          {translate(mob.id)}
        </p>
        <div className="flex flex-wrap gap-x-2 text-xs text-gray-400">
          {mob.killed > 0 && <span>처치 <span className="text-red-400">{mob.killed}</span></span>}
          {mob.killedBy > 0 && <span>죽음 <span className="text-gray-300">{mob.killedBy}</span></span>}
        </div>
      </div>
    </div>
  );
};

export default PlayerStatsPage;
