"use client";

import { useState, useEffect, useCallback, useRef } from "react";
import type {
  CacheLevel,
  CacheStats,
  ContentType,
  CacheStatus,
  CacheMetrics,
} from "./types";

// 캐시 매니저 인스턴스 (실제 구현에서는 Context에서 제공)
interface CacheManagerInterface {
  get<T>(
    key: string,
    contentType: ContentType,
    options?: {
      levels?: CacheLevel[];
      fallback?: () => Promise<T>;
    }
  ): Promise<{ data: T | null; status: CacheStatus; level?: CacheLevel }>;
  set<T>(
    key: string,
    data: T,
    contentType: ContentType,
    options?: {
      ttl?: number;
      levels?: CacheLevel[];
      tags?: string[];
    }
  ): Promise<boolean>;
  invalidate(
    pattern: string | string[],
    options?: {
      levels?: CacheLevel[];
      strategy?: "key" | "tag" | "pattern";
    }
  ): Promise<number>;
  getStats(): CacheStats;
  healthCheck(): Promise<{
    healthy: boolean;
    levels: Map<CacheLevel, boolean>;
    issues: string[];
  }>;
}

// 글로벌 캐시 매니저 (실제로는 Context Provider에서 제공)
declare const cacheManager: CacheManagerInterface;

/**
 * 캐시된 데이터를 조회하고 관리하는 훅
 */
export function useCache<T>(
  key: string,
  contentType: ContentType,
  options?: {
    levels?: CacheLevel[];
    fallback?: () => Promise<T>;
    enabled?: boolean;
    refetchInterval?: number;
    staleTime?: number;
  }
) {
  const [data, setData] = useState<T | null>(null);
  const [status, setStatus] = useState<CacheStatus>("miss");
  const [level, setLevel] = useState<CacheLevel | undefined>(undefined);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [lastUpdated, setLastUpdated] = useState<Date | null>(null);

  const fetchTimeRef = useRef<Date | null>(null);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);

  const fetchData = useCallback(async () => {
    if (!options?.enabled) return;

    setLoading(true);
    setError(null);

    try {
      const result = await cacheManager.get(key, contentType, {
        levels: options?.levels,
        fallback: options?.fallback,
      });

      setData(result.data);
      setStatus(result.status);
      setLevel(result.level);
      setLastUpdated(new Date());
      fetchTimeRef.current = new Date();
    } catch (err) {
      setError(err instanceof Error ? err.message : "캐시 조회 오류");
      setStatus("error");
    } finally {
      setLoading(false);
    }
  }, [key, contentType, options?.levels, options?.fallback, options?.enabled]);

  // Stale time 체크
  const isStale = useCallback(() => {
    if (!fetchTimeRef.current || !options?.staleTime) return false;
    return Date.now() - fetchTimeRef.current.getTime() > options.staleTime;
  }, [options?.staleTime]);

  // 데이터 무효화
  const invalidate = useCallback(async () => {
    await cacheManager.invalidate(key, { levels: options?.levels });
    await fetchData();
  }, [key, options?.levels, fetchData]);

  // 데이터 설정
  const setCache = useCallback(
    async (
      newData: T,
      cacheOptions?: {
        ttl?: number;
        tags?: string[];
      }
    ) => {
      await cacheManager.set(key, newData, contentType, {
        levels: options?.levels,
        ...cacheOptions,
      });
      setData(newData);
      setLastUpdated(new Date());
      fetchTimeRef.current = new Date();
    },
    [key, contentType, options?.levels]
  );

  // 초기 로드 및 인터벌 설정
  useEffect(() => {
    if (options?.enabled !== false) {
      fetchData();
    }

    // 자동 갱신 설정
    if (options?.refetchInterval) {
      intervalRef.current = setInterval(() => {
        if (!loading && (isStale() || !data)) {
          fetchData();
        }
      }, options.refetchInterval);
    }

    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
      }
    };
  }, [
    fetchData,
    options?.refetchInterval,
    options?.enabled,
    loading,
    data,
    isStale,
  ]);

  return {
    data,
    status,
    level,
    loading,
    error,
    lastUpdated,
    isStale: isStale(),
    refetch: fetchData,
    invalidate,
    setCache,
  };
}

/**
 * 캐시 통계를 조회하는 훅
 */
export function useCacheStats(refreshInterval = 5000) {
  const [stats, setStats] = useState<CacheStats | null>(null);
  const [loading, setLoading] = useState(true);

  const fetchStats = useCallback(() => {
    try {
      const currentStats = cacheManager.getStats();
      setStats(currentStats);
    } catch (error) {
      console.error("캐시 통계 조회 오류:", error);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    fetchStats();

    const interval = setInterval(fetchStats, refreshInterval);
    return () => clearInterval(interval);
  }, [fetchStats, refreshInterval]);

  return {
    stats,
    loading,
    refresh: fetchStats,
  };
}

/**
 * 캐시 헬스 체크 훅
 */
export function useCacheHealth(checkInterval = 30000) {
  const [health, setHealth] = useState<{
    healthy: boolean;
    levels: Map<CacheLevel, boolean>;
    issues: string[];
  } | null>(null);
  const [checking, setChecking] = useState(false);

  const checkHealth = useCallback(async () => {
    setChecking(true);
    try {
      const healthResult = await cacheManager.healthCheck();
      setHealth(healthResult);
    } catch (error) {
      console.error("캐시 헬스 체크 오류:", error);
      setHealth({
        healthy: false,
        levels: new Map(),
        issues: ["헬스 체크 실행 실패"],
      });
    } finally {
      setChecking(false);
    }
  }, []);

  useEffect(() => {
    checkHealth();

    const interval = setInterval(checkHealth, checkInterval);
    return () => clearInterval(interval);
  }, [checkHealth, checkInterval]);

  return {
    health,
    checking,
    checkHealth,
  };
}

/**
 * 여러 키를 동시에 캐시에서 조회하는 훅
 */
export function useMultiCache<T>(
  keys: Array<{
    key: string;
    contentType: ContentType;
    fallback?: () => Promise<T>;
  }>,
  options?: {
    levels?: CacheLevel[];
    enabled?: boolean;
  }
) {
  const [results, setResults] = useState<
    Map<
      string,
      {
        data: T | null;
        status: CacheStatus;
        level?: CacheLevel;
      }
    >
  >(new Map());
  const [loading, setLoading] = useState(false);
  const [errors, setErrors] = useState<Map<string, string>>(new Map());

  const fetchAll = useCallback(async () => {
    if (!options?.enabled || keys.length === 0) return;

    setLoading(true);
    setErrors(new Map());

    const newResults = new Map();
    const newErrors = new Map();

    await Promise.allSettled(
      keys.map(async ({ key, contentType, fallback }) => {
        try {
          const result = await cacheManager.get(key, contentType, {
            levels: options?.levels,
            fallback,
          });
          newResults.set(key, result);
        } catch (error) {
          newErrors.set(
            key,
            error instanceof Error ? error.message : "오류 발생"
          );
        }
      })
    );

    setResults(newResults);
    setErrors(newErrors);
    setLoading(false);
  }, [keys, options?.levels, options?.enabled]);

  const invalidateAll = useCallback(async () => {
    const keyList = keys.map(({ key }) => key);
    await cacheManager.invalidate(keyList, { levels: options?.levels });
    await fetchAll();
  }, [keys, options?.levels, fetchAll]);

  useEffect(() => {
    if (options?.enabled !== false) {
      fetchAll();
    }
  }, [fetchAll, options?.enabled]);

  return {
    results,
    loading,
    errors,
    refetchAll: fetchAll,
    invalidateAll,
  };
}

/**
 * 캐시 무효화를 위한 훅
 */
export function useCacheInvalidation() {
  const [invalidating, setInvalidating] = useState(false);

  const invalidatePattern = useCallback(
    async (
      pattern: string | string[],
      options?: {
        levels?: CacheLevel[];
        strategy?: "key" | "tag" | "pattern";
      }
    ) => {
      setInvalidating(true);
      try {
        const count = await cacheManager.invalidate(pattern, options);
        return count;
      } catch (error) {
        console.error("캐시 무효화 오류:", error);
        throw error;
      } finally {
        setInvalidating(false);
      }
    },
    []
  );

  const invalidateByTag = useCallback(
    async (tags: string | string[], levels?: CacheLevel[]) => {
      return invalidatePattern(Array.isArray(tags) ? tags : [tags], {
        levels,
        strategy: "tag",
      });
    },
    [invalidatePattern]
  );

  const invalidateByKey = useCallback(
    async (keys: string | string[], levels?: CacheLevel[]) => {
      return invalidatePattern(keys, {
        levels,
        strategy: "key",
      });
    },
    [invalidatePattern]
  );

  return {
    invalidating,
    invalidatePattern,
    invalidateByTag,
    invalidateByKey,
  };
}

/**
 * 실시간 캐시 메트릭 훅
 */
export function useCacheMetrics(updateInterval = 1000) {
  const [metrics, setMetrics] = useState<CacheMetrics | null>(null);

  useEffect(() => {
    const updateMetrics = () => {
      try {
        const stats = cacheManager.getStats();
        setMetrics(stats.overall);
      } catch (error) {
        console.error("메트릭 업데이트 오류:", error);
      }
    };

    updateMetrics();
    const interval = setInterval(updateMetrics, updateInterval);

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

  return metrics;
}
