import { useState, useEffect, useRef, useCallback } from 'react';
import { getLatestData, SensorData } from '../services/api';

export type ConnectionStatus = 'connected' | 'disconnected' | 'error' | 'retrying' | 'connecting';

export interface UseRealTimeDataReturn {
  data: SensorData[];
  isConnected: boolean;
  connectionStatus: ConnectionStatus;
  dataSource: 'polling';
  lastUpdate: string;
  error: string | null;
  loading: boolean;
  refetch: () => Promise<void>;
  retryCount: Map<string, number>;
}

const POLLING_INTERVAL = 5000; // 5초
const CACHE_DURATION = 30 * 1000; // 30초
const RETRY_DELAY = 1000; // 1초

export const useRealTimeData = (deviceIds: string[]): UseRealTimeDataReturn => {
  const [data, setData] = useState<SensorData[]>([]);
  const [dataSource, setDataSource] = useState<'polling'>('polling');
  const [lastUpdate, setLastUpdate] = useState<string>('');
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [connectionStatus, setConnectionStatus] = useState<ConnectionStatus>('connecting');
  
  const cacheRef = useRef<Map<string, { data: SensorData; timestamp: number }>>(new Map());
  const pollingTimerRef = useRef<NodeJS.Timeout | null>(null);
  const retryTimersRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
  const mountedRef = useRef(true);
  const previousDataRef = useRef<Map<string, SensorData>>(new Map());
  const retryCountRef = useRef<Map<string, number>>(new Map());
  const maxRetries = 3;

  // 컴포넌트 언마운트 시 정리
  useEffect(() => {
    return () => {
      mountedRef.current = false;
      if (pollingTimerRef.current) {
        clearInterval(pollingTimerRef.current);
      }
      // 재시도 타이머들 정리
      retryTimersRef.current.forEach(timer => clearTimeout(timer));
      retryTimersRef.current.clear();
      cacheRef.current.clear();
      previousDataRef.current.clear();
      retryCountRef.current.clear();
    };
  }, []);

  // 폴링 시작
  useEffect(() => {
    if (deviceIds.length > 0) {
      console.log('🔄 폴링 모드 시작 - 디바이스:', deviceIds);
      console.log('📡 API URL:', process.env.REACT_APP_API_URL || 'http://sensor.geumdo.net');
      setConnectionStatus('connecting');
      startPolling();
    }

    return () => {
      if (pollingTimerRef.current) {
        clearInterval(pollingTimerRef.current);
        pollingTimerRef.current = null;
      }
    };
  }, [deviceIds]);

  // 캐시에서 데이터 업데이트
  const updateDataFromCache = useCallback(() => {
    const now = Date.now();
    const validData: SensorData[] = [];
    
    cacheRef.current.forEach((item, deviceId) => {
      if (now - item.timestamp <= CACHE_DURATION) {
        validData.push(item.data);
      }
    });

    if (mountedRef.current) {
      setData(validData);
      setLoading(false);
      console.log('✅ 캐시에서 데이터 업데이트 완료 - 유효한 데이터:', validData.length, '개');
      
      // 연결 상태 업데이트
      if (validData.length > 0) {
        setConnectionStatus('connected');
        setError(null);
      } else {
        setConnectionStatus('disconnected');
      }
    }
  }, []);

  // 폴링 시작
  const startPolling = useCallback(() => {
    if (pollingTimerRef.current) {
      clearInterval(pollingTimerRef.current);
    }

    console.log('🔄 폴링 타이머 시작 - 간격:', POLLING_INTERVAL / 1000, '초');
    console.log('📊 대상 디바이스 수:', deviceIds.length);
    
    // 즉시 첫 번째 데이터 가져오기
    fetchDataFromAPI();

    // 주기적 폴링 설정
    pollingTimerRef.current = setInterval(() => {
      console.log('⏰ 폴링 타이머 실행 - 새로운 데이터 요청');
      console.log('🕐 현재 시간:', new Date().toISOString());
      fetchDataFromAPI();
    }, POLLING_INTERVAL);
  }, [deviceIds]);

  // 재시도 로직
  const scheduleRetry = useCallback((deviceId: string) => {
    const currentRetryCount = retryCountRef.current.get(deviceId) || 0;
    const newRetryCount = currentRetryCount + 1;
    
    if (newRetryCount <= maxRetries) {
      console.log(`🔄 디바이스 ${deviceId} ${RETRY_DELAY}ms 후 재시도 예정 (${newRetryCount}/${maxRetries})`);
      setConnectionStatus('retrying');
      
      const retryTimer = setTimeout(() => {
        if (mountedRef.current) {
          console.log(`🔄 디바이스 ${deviceId} 재시도 실행 (${newRetryCount}/${maxRetries})`);
          fetchSingleDeviceData(deviceId);
        }
      }, RETRY_DELAY);
      
      retryTimersRef.current.set(deviceId, retryTimer);
    } else {
      console.error(`🚨 디바이스 ${deviceId} 최대 재시도 횟수 초과. 다음 폴링까지 대기합니다.`);
      setConnectionStatus('error');
      setError(`디바이스 ${deviceId} 연결 실패 (최대 재시도 횟수 초과)`);
    }
  }, []);

  // 단일 디바이스 데이터 가져오기
  const fetchSingleDeviceData = useCallback(async (deviceId: string) => {
    try {
      console.log(`📡 디바이스 ${deviceId} 데이터 요청 시작`);
      const startTime = Date.now();
      
      const sensorData = await getLatestData(deviceId);
      const responseTime = Date.now() - startTime;
      
      if (sensorData) {
        console.log(`✅ 디바이스 ${deviceId} 데이터 수신 성공 (응답시간: ${responseTime}ms)`);
        
        // 재시도 카운트 리셋
        retryCountRef.current.set(deviceId, 0);
        
        // 이전 데이터와 비교하여 변경사항 확인
        const previousData = previousDataRef.current.get(deviceId);
        const hasChanged = !previousData || 
          previousData.temperature !== sensorData.temperature ||
          previousData.humidity !== sensorData.humidity ||
          previousData.pm10 !== sensorData.pm10 ||
          previousData.pm25 !== sensorData.pm25 ||
          previousData.pressure !== sensorData.pressure ||
          previousData.illumination !== sensorData.illumination ||
          previousData.tvoc !== sensorData.tvoc ||
          previousData.co2 !== sensorData.co2 ||
          previousData.o2 !== sensorData.o2 ||
          previousData.co !== sensorData.co;

        if (hasChanged) {
          console.log('🔄 데이터 변경 감지:', deviceId);
          console.log('📊 변경된 센서 데이터:', {
            device_id: sensorData.device_id,
            temperature: sensorData.temperature,
            humidity: sensorData.humidity,
            pm10: sensorData.pm10,
            pm25: sensorData.pm25,
            pressure: sensorData.pressure,
            illumination: sensorData.illumination,
            tvoc: sensorData.tvoc,
            co2: sensorData.co2,
            o2: sensorData.o2,
            co: sensorData.co,
            recorded_time: sensorData.recorded_time
          });
        } else {
          console.log('✅ 데이터 변경 없음:', deviceId);
        }

        // 현재 데이터를 이전 데이터로 저장
        previousDataRef.current.set(deviceId, { ...sensorData });
        
        cacheRef.current.set(deviceId, {
          data: sensorData,
          timestamp: Date.now()
        });
        
        return sensorData;
      } else {
        console.warn(`⚠️ 디바이스 ${deviceId}에서 데이터를 받지 못했습니다.`);
        return null;
      }
    } catch (err) {
      console.error(`❌ 디바이스 ${deviceId} 데이터 가져오기 실패:`, err);
      scheduleRetry(deviceId);
      return null;
    }
  }, [scheduleRetry]);

  // API에서 데이터 가져오기
  const fetchDataFromAPI = useCallback(async () => {
    if (deviceIds.length === 0) {
      console.log('⚠️ 폴링 대상 디바이스가 없습니다.');
      return;
    }

    try {
      console.log('📡 API 데이터 요청 시작 - 디바이스:', deviceIds);
      console.log('🔧 요청 파라미터:', { deviceIds, timestamp: new Date().toISOString() });
      
      const promises = deviceIds.map(deviceId => fetchSingleDeviceData(deviceId));

      const results = await Promise.all(promises);
      const successCount = results.filter(r => r !== null).length;
      const failureCount = results.length - successCount;
      
      console.log(`📊 API 요청 결과 - 성공: ${successCount}개, 실패: ${failureCount}개`);
      
      if (mountedRef.current) {
        updateDataFromCache();
        setLastUpdate(new Date().toISOString());
        
        // 연결 상태 업데이트
        if (successCount > 0) {
          setConnectionStatus('connected');
          setError(null);
        } else if (failureCount > 0) {
          setConnectionStatus('error');
        }
      }
    } catch (err) {
      if (mountedRef.current) {
        const errorMessage = err instanceof Error ? err.message : '알 수 없는 오류';
        setError(`데이터를 가져오는 중 오류가 발생했습니다: ${errorMessage}`);
        setConnectionStatus('error');
        console.error('❌ API 데이터 가져오기 실패:', err);
        console.error('🔍 에러 상세 정보:', {
          message: err instanceof Error ? err.message : 'Unknown error',
          stack: err instanceof Error ? err.stack : 'No stack trace',
          timestamp: new Date().toISOString()
        });
      }
    }
  }, [deviceIds, updateDataFromCache, fetchSingleDeviceData]);

  // 수동 새로고침
  const refetch = useCallback(async (): Promise<void> => {
    if (mountedRef.current) {
      console.log('🔄 수동 새로고침 시작');
      setLoading(true);
      setError(null);
      setConnectionStatus('connecting');
      
      // 캐시 무효화
      cacheRef.current.clear();
      previousDataRef.current.clear();
      retryCountRef.current.clear();
      
      // 재시도 타이머들 정리
      retryTimersRef.current.forEach(timer => clearTimeout(timer));
      retryTimersRef.current.clear();
      
      console.log('🗑️ 캐시 및 재시도 카운트 초기화 완료');
      
      // API를 통한 새로고침
      await fetchDataFromAPI();
      console.log('✅ 수동 새로고침 완료');
    }
  }, [fetchDataFromAPI]);

  // 디바이스 ID 변경 시 처리
  useEffect(() => {
    if (deviceIds.length > 0) {
      console.log('🔄 디바이스 목록 변경:', deviceIds);
      
      // 캐시에서 더 이상 사용하지 않는 디바이스 데이터 제거
      const currentDeviceIds = new Set(deviceIds);
      const cachedDeviceIds = Array.from(cacheRef.current.keys());
      
      cachedDeviceIds.forEach(deviceId => {
        if (!currentDeviceIds.has(deviceId)) {
          console.log('🗑️ 디바이스 제거:', deviceId);
          cacheRef.current.delete(deviceId);
          previousDataRef.current.delete(deviceId);
          retryCountRef.current.delete(deviceId);
          
          // 재시도 타이머도 정리
          const retryTimer = retryTimersRef.current.get(deviceId);
          if (retryTimer) {
            clearTimeout(retryTimer);
            retryTimersRef.current.delete(deviceId);
          }
        }
      });

      // 데이터 업데이트
      updateDataFromCache();
    }
  }, [deviceIds, updateDataFromCache]);

  // 폴링 타이머 정리
  useEffect(() => {
    return () => {
      if (pollingTimerRef.current) {
        clearInterval(pollingTimerRef.current);
        pollingTimerRef.current = null;
      }
    };
  }, []);

  return {
    data,
    isConnected: connectionStatus === 'connected',
    connectionStatus,
    dataSource,
    lastUpdate,
    error,
    loading,
    refetch,
    retryCount: retryCountRef.current
  };
}; 