/**
 * Entity 조인 최적화를 위한 커스텀 훅
 * 배치 로딩과 메모이제이션을 통한 성능 최적화
 */

import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import { codeCache } from "@/lib/caching/codeCache";

interface ColumnMetaInfo {
  webType?: string;
  codeCategory?: string;
}

interface OptimizationConfig {
  enableBatchLoading?: boolean;
  preloadCommonCodes?: boolean;
  cacheTimeout?: number;
  maxBatchSize?: number;
}

interface OptimizationMetrics {
  cacheHitRate: number;
  totalRequests: number;
  batchLoadCount: number;
  averageResponseTime: number;
}

/**
 * Entity 조인 최적화 훅
 * - 코드 캐시 배치 로딩
 * - 성능 메트릭 추적
 * - 스마트 프리로딩
 */
export function useEntityJoinOptimization(columnMeta: Record<string, ColumnMetaInfo>, config: OptimizationConfig = {}) {
  const {
    enableBatchLoading = true,
    preloadCommonCodes = true,
    cacheTimeout = 5 * 60 * 1000, // 5분
    maxBatchSize = 10,
  } = config;

  // 성능 메트릭 상태
  const [metrics, setMetrics] = useState<OptimizationMetrics>({
    cacheHitRate: 0,
    totalRequests: 0,
    batchLoadCount: 0,
    averageResponseTime: 0,
  });

  // 로딩 상태
  const [isOptimizing, setIsOptimizing] = useState(false);
  const [loadingCategories, setLoadingCategories] = useState<Set<string>>(new Set());

  // 메트릭 추적용 refs
  const requestTimes = useRef<number[]>([]);
  const totalRequests = useRef(0);
  const cacheHits = useRef(0);
  const batchLoadCount = useRef(0);
  
  // 변환된 값 캐시 (중복 변환 방지)
  const convertedCache = useRef(new Map<string, string>());
  
  // 초기화 완료 플래그 (무한 루프 방지)
  const initialLoadDone = useRef(false);

  // 공통 코드 카테고리 추출 (메모이제이션)
  const codeCategories = useMemo(() => {
    return Object.values(columnMeta)
      .filter((meta) => meta.webType === "code" && meta.codeCategory)
      .map((meta) => meta.codeCategory!)
      .filter((category, index, self) => self.indexOf(category) === index); // 중복 제거
  }, [columnMeta]);

  // 일반적으로 자주 사용되는 코드 카테고리들
  const commonCodeCategories = useMemo(
    () => [
      "USER_STATUS", // 사용자 상태
      "DEPT_TYPE", // 부서 유형
      "DOC_STATUS", // 문서 상태
      "APPROVAL_STATUS", // 승인 상태
      "PRIORITY", // 우선순위
      "YES_NO", // 예/아니오
      "ACTIVE_INACTIVE", // 활성/비활성
    ],
    [],
  );

  /**
   * 배치 코드 로딩
   */
  const batchLoadCodes = useCallback(
    async (categories: string[]): Promise<void> => {
      if (!enableBatchLoading || categories.length === 0) return;

      const startTime = Date.now();
      setIsOptimizing(true);

      try {
        // 배치 크기별로 분할하여 로딩
        const batches: string[][] = [];
        for (let i = 0; i < categories.length; i += maxBatchSize) {
          batches.push(categories.slice(i, i + maxBatchSize));
        }

        // console.log(`🔄 배치 코드 로딩 시작: ${categories.length}개 카테고리 (${batches.length}개 배치)`);

        for (const batch of batches) {
          // 로딩 상태 업데이트
          setLoadingCategories((prev) => new Set([...prev, ...batch]));

          // 배치 로딩 실행
          await codeCache.preloadCodes(batch);
          batchLoadCount.current += 1;

          // 로딩 완료된 카테고리 제거
          setLoadingCategories((prev) => {
            const newSet = new Set(prev);
            batch.forEach((category) => newSet.delete(category));
            return newSet;
          });

          // 배치 간 짧은 지연 (서버 부하 방지)
          if (batches.length > 1) {
            await new Promise((resolve) => setTimeout(resolve, 100));
          }
        }

        const responseTime = Date.now() - startTime;
        requestTimes.current.push(responseTime);

        // console.log(`✅ 배치 코드 로딩 완료: ${responseTime}ms`);
      } catch (error) {
        console.error("❌ 배치 코드 로딩 실패:", error);
      } finally {
        setIsOptimizing(false);
        setLoadingCategories(new Set());
      }
    },
    [enableBatchLoading, maxBatchSize],
  );

  /**
   * 공통 코드 프리로딩
   */
  const preloadCommonCodesOnMount = useCallback(async (): Promise<void> => {
    if (!preloadCommonCodes) return;

    // console.log("🚀 공통 코드 프리로딩 시작");

    // 현재 테이블의 코드 카테고리와 공통 카테고리 합치기
    const allCategories = [...new Set([...codeCategories, ...commonCodeCategories])];

    if (allCategories.length > 0) {
      await batchLoadCodes(allCategories);
    }
  }, [preloadCommonCodes, codeCategories, commonCodeCategories, batchLoadCodes]);

  /**
   * 성능 메트릭 업데이트
   */
  const updateMetrics = useCallback(() => {
    const cacheInfo = codeCache.getCacheInfo();
    const avgResponseTime =
      requestTimes.current.length > 0
        ? requestTimes.current.reduce((sum, time) => sum + time, 0) / requestTimes.current.length
        : 0;

    setMetrics({
      cacheHitRate: cacheInfo.hitRate,
      totalRequests: totalRequests.current,
      batchLoadCount: batchLoadCount.current,
      averageResponseTime: Math.round(avgResponseTime),
    });
  }, []);

  /**
   * 최적화된 코드 변환 함수
   */
  const optimizedConvertCode = useCallback(
    (categoryCode: string, codeValue: string): string => {
      const startTime = Date.now();
      totalRequests.current += 1;

      // 🎯 중복 호출 방지: 이미 변환된 값인지 확인
      const cacheKey = `${categoryCode}:${codeValue}`;
      if (convertedCache.current.has(cacheKey)) {
        return convertedCache.current.get(cacheKey)!;
      }

      // 🎯 디버깅: 캐시 상태 로깅 (빈도 줄이기)
      if (totalRequests.current % 10 === 1) { // 10번마다 한 번만 로깅
        console.log(`🔍 optimizedConvertCode 호출: categoryCode="${categoryCode}", codeValue="${codeValue}"`);
      }

      // 캐시에서 동기적으로 조회 시도
      const syncResult = codeCache.getCodeSync(categoryCode);
      if (totalRequests.current % 10 === 1) {
        console.log(`🔍 getCodeSync("${categoryCode}") 결과:`, syncResult);
      }

      // 🎯 캐시 내용 상세 로깅 (키값들 확인) - 빈도 줄이기
      if (syncResult && totalRequests.current % 10 === 1) {
        console.log(`🔍 캐시 키값들:`, Object.keys(syncResult));
        console.log(`🔍 캐시 전체 데이터:`, JSON.stringify(syncResult, null, 2));
      }

      if (syncResult && Array.isArray(syncResult)) {
        cacheHits.current += 1;
        if (totalRequests.current % 10 === 1) {
          console.log(`🔍 배열에서 코드 검색: codeValue="${codeValue}"`);
          console.log(
            `🔍 캐시 배열 내용:`,
            syncResult.map((item) => ({
              code_value: item.code_value,
              code_name: item.code_name,
            })),
          );
        }

        // 배열에서 해당 code_value를 가진 항목 찾기
        const foundCode = syncResult.find(
          (item) => String(item.code_value).toUpperCase() === String(codeValue).toUpperCase(),
        );

        const result = foundCode ? foundCode.code_name : codeValue;
        
        // 변환 결과를 캐시에 저장
        convertedCache.current.set(cacheKey, result);
        
        if (totalRequests.current % 10 === 1) {
          console.log(`🔍 최종 결과: "${codeValue}" → "${result}"`, { foundCode });
        }

        // 응답 시간 추적 (캐시 히트)
        requestTimes.current.push(Date.now() - startTime);
        if (requestTimes.current.length > 100) {
          requestTimes.current = requestTimes.current.slice(-50); // 최근 50개만 유지
        }

        return result;
      }

      console.log(`⚠️ 캐시 미스: categoryCode="${categoryCode}" - 비동기 로딩 트리거`);

      // 캐시 미스인 경우 비동기 로딩 트리거 (백그라운드)
      codeCache
        .getCodeAsync(categoryCode)
        .then(() => {
          console.log(`✅ 비동기 로딩 완료: categoryCode="${categoryCode}"`);
          updateMetrics();
        })
        .catch((err) => {
          console.warn(`백그라운드 코드 로딩 실패 [${categoryCode}]:`, err);
        });

      return codeValue || "";
    },
    [updateMetrics],
  );

  /**
   * 캐시 상태 조회
   */
  const getCacheStatus = useCallback(() => {
    const cacheInfo = codeCache.getCacheInfo();
    const loadedCategories = codeCategories.filter((category) => {
      const syncData = codeCache.getCodeSync(category);
      return syncData !== null;
    });

    return {
      totalCategories: codeCategories.length,
      loadedCategories: loadedCategories.length,
      loadingCategories: Array.from(loadingCategories),
      cacheInfo,
      isFullyLoaded: loadedCategories.length === codeCategories.length && !isOptimizing,
    };
  }, [codeCategories, loadingCategories, isOptimizing]);

  /**
   * 수동 캐시 새로고침
   */
  const refreshCache = useCallback(
    async (categories?: string[]): Promise<void> => {
      const targetCategories = categories || codeCategories;

      // 기존 캐시 무효화
      targetCategories.forEach((category) => {
        codeCache.invalidate(category);
      });

      // 다시 로딩
      await batchLoadCodes(targetCategories);
      updateMetrics();
    },
    [codeCategories, batchLoadCodes, updateMetrics],
  );

  // 초기화 시 공통 코드 프리로딩 (한 번만 실행)
  useEffect(() => {
    // 이미 초기화되었으면 스킵 (무한 루프 방지)
    if (initialLoadDone.current) return;
    initialLoadDone.current = true;
    
    preloadCommonCodesOnMount();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 컬럼 메타 변경 시 필요한 코드 추가 로딩
  // 이미 로딩 중이면 스킵하여 무한 루프 방지
  const loadedCategoriesRef = useRef<Set<string>>(new Set());
  
  useEffect(() => {
    // 이미 최적화 중이거나 초기화 전이면 스킵
    if (isOptimizing) return;
    
    if (codeCategories.length > 0) {
      const unloadedCategories = codeCategories.filter((category) => {
        // 이미 로드 요청을 보낸 카테고리는 스킵
        if (loadedCategoriesRef.current.has(category)) return false;
        return codeCache.getCodeSync(category) === null;
      });

      if (unloadedCategories.length > 0) {
        // 로딩 요청 카테고리 기록
        unloadedCategories.forEach(cat => loadedCategoriesRef.current.add(cat));
        console.log(`🔄 새로운 코드 카테고리 감지, 추가 로딩: ${unloadedCategories.join(", ")}`);
        batchLoadCodes(unloadedCategories);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [codeCategories.join(",")]); // 배열 내용 기반 의존성

  // 주기적으로 메트릭 업데이트
  useEffect(() => {
    const interval = setInterval(updateMetrics, 10000); // 10초마다
    return () => clearInterval(interval);
  }, [updateMetrics]);

  return {
    // 상태
    isOptimizing,
    loadingCategories: Array.from(loadingCategories),
    metrics,

    // 기능
    optimizedConvertCode,
    batchLoadCodes,
    refreshCache,
    getCacheStatus,

    // 유틸리티
    codeCategories,
    commonCodeCategories,
  };
}
