'use client';

import { useState, useEffect, useCallback, useRef } from 'react';
import { Product } from '@/types/product';
import { DataChunkManager } from '@/lib/data-chunking';
import { redisCache, cacheHelpers } from '@/lib/redis-cache';

export interface UseProductsOptions {
  category?: string;
  search?: string;
  sortBy?: 'name' | 'price' | 'created_at';
  sortOrder?: 'asc' | 'desc';
  limit?: number;
  enableCache?: boolean;
  enableChunking?: boolean;
  preloadNext?: boolean;
  chunkSize?: number;
}

export interface ProductsState {
  products: Product[];
  loading: boolean;
  error: string | null;
  hasMore: boolean;
  currentPage: number;
  totalPages: number;
  totalCount: number;
  cacheHit: boolean;
}

export interface ProductsActions {
  loadMore: () => Promise<void>;
  refresh: () => Promise<void>;
  reset: () => void;
  loadPage: (page: number) => Promise<void>;
  preloadNextPage: () => Promise<void>;
  getStats: () => {
    cache: unknown;
    chunks: unknown;
    memory: string;
  };
}

/**
 * Enhanced products hook with chunking and Redis-like caching
 */
export function useEnhancedProducts(options: UseProductsOptions = {}): [ProductsState, ProductsActions] {
  const {
    category,
    search,
    sortBy = 'created_at',
    sortOrder = 'desc',
    limit = 20,
    enableCache = true,
    enableChunking = true,
    preloadNext = true,
    chunkSize = 20,
  } = options;

  // State
  const [state, setState] = useState<ProductsState>({
    products: [],
    loading: false,
    error: null,
    hasMore: true,
    currentPage: 0,
    totalPages: 0,
    totalCount: 0,
    cacheHit: false,
  });

  // Refs for cleanup
  const abortControllerRef = useRef<AbortController | null>(null);
  const chunkManagerRef = useRef<DataChunkManager<Product> | undefined>(undefined);

  // Initialize chunk manager
  useEffect(() => {
    if (enableChunking) {
      chunkManagerRef.current = new DataChunkManager<Product>({
        chunkSize,
        maxConcurrentChunks: 3,
        retryAttempts: 3,
        retryDelay: 1000,
      });
    }
  }, [enableChunking, chunkSize]);

  // Generate cache key
  const getCacheKey = useCallback((page: number = 1) => {
    const filters = {
      category: category || '',
      search: search || '',
      sortBy,
      sortOrder,
      page,
      limit,
    };
    return `products:${Object.entries(filters)
      .filter(([, value]) => value !== '' && value !== undefined)
      .map(([key, value]) => `${key}=${value}`)
      .join('&')}`;
  }, [category, search, sortBy, sortOrder, limit]);

  // Build API URL
  const buildApiUrl = useCallback((page: number = 1) => {
    const params = new URLSearchParams({
      page: page.toString(),
      limit: limit.toString(),
      sortBy,
      sortOrder,
    });

    if (category) params.set('category', category);
    if (search) params.set('search', search);

    return `/api/products?${params.toString()}`;
  }, [category, search, sortBy, sortOrder, limit]);

  // Fetch products function
  const fetchProducts = useCallback(async (
    page: number,
    append: boolean = false
  ): Promise<{ products: Product[]; totalPages: number; totalCount: number; hasMore: boolean }> => {
    const cacheKey = getCacheKey(page);
    
    // Try cache first
    if (enableCache) {
      const cached = redisCache.get<{
        products: Product[];
        totalPages: number;
        totalCount: number;
        hasMore: boolean;
      }>(cacheKey);
      
      if (cached) {
        setState(prev => ({
          ...prev,
          cacheHit: true,
          ...(append 
            ? { products: [...prev.products, ...cached.products] }
            : { products: cached.products }
          ),
          totalPages: cached.totalPages,
          totalCount: cached.totalCount,
          hasMore: cached.hasMore,
          currentPage: page,
          loading: false,
          error: null,
        }));
        return cached;
      }
    }

    // Cancel previous request
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }
    abortControllerRef.current = new AbortController();

    try {
      setState(prev => ({ ...prev, loading: true, error: null, cacheHit: false }));

      let result;

      if (enableChunking && chunkManagerRef.current) {
        // Use chunking for large datasets
        const chunkResult = await chunkManagerRef.current.loadChunk(
          buildApiUrl(page),
          page,
          { category, search, sortBy, sortOrder },
          async (url, signal) => {
            const response = await fetch(url, { signal });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            return response;
          }
        );

        result = {
          products: chunkResult.data,
          totalPages: chunkResult.totalPages,
          totalCount: chunkResult.totalPages * limit,
          hasMore: chunkResult.hasMore,
        };
      } else {
        // Regular fetch
        const response = await fetch(buildApiUrl(page), {
          signal: abortControllerRef.current.signal,
        });

        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }

        const data = await response.json();
        result = {
          products: data.data || data.products || [],
          totalPages: data.totalPages || Math.ceil((data.total || 0) / limit),
          totalCount: data.total || 0,
          hasMore: data.hasMore ?? (data.data?.length === limit),
        };
      }

      // Cache the result
      if (enableCache) {
        redisCache.set(cacheKey, result, 15 * 60 * 1000); // 15 minutes
        
        // Also cache by category for quick access
        if (category) {
          cacheHelpers.cacheProductsByCategory(category, result.products);
        }
      }

      setState(prev => ({
        ...prev,
        ...(append 
          ? { products: [...prev.products, ...result.products] }
          : { products: result.products }
        ),
        totalPages: result.totalPages,
        totalCount: result.totalCount,
        hasMore: result.hasMore,
        currentPage: page,
        loading: false,
        error: null,
      }));

      return result;
    } catch (error: unknown) {
      if (error instanceof Error && error.name === 'AbortError') return { products: [], totalPages: 0, totalCount: 0, hasMore: false };
      
      const errorMessage = error instanceof Error ? error.message : 'Failed to fetch products';
      setState(prev => ({
        ...prev,
        loading: false,
        error: errorMessage,
      }));
      throw error;
    }
  }, [
    getCacheKey,
    enableCache,
    buildApiUrl,
    enableChunking,
    category,
    search,
    sortBy,
    sortOrder,
    limit,
  ]);

  // Load more products (pagination)
  const loadMore = useCallback(async () => {
    if (state.loading || !state.hasMore) return;
    
    const nextPage = state.currentPage + 1;
    await fetchProducts(nextPage, true);
    
    // Preload next page if enabled
    if (preloadNext && enableChunking && chunkManagerRef.current) {
      chunkManagerRef.current.preloadNextChunks(
        buildApiUrl(nextPage + 1),
        nextPage,
        { category, search, sortBy, sortOrder },
        1
      );
    }
  }, [state.loading, state.hasMore, state.currentPage, fetchProducts, preloadNext, enableChunking, buildApiUrl, category, search, sortBy, sortOrder]);

  // Load specific page
  const loadPage = useCallback(async (page: number) => {
    await fetchProducts(page, false);
  }, [fetchProducts]);

  // Preload next page
  const preloadNextPage = useCallback(async () => {
    if (!preloadNext || !enableChunking || !chunkManagerRef.current) return;
    
    const nextPage = state.currentPage + 1;
    chunkManagerRef.current.preloadNextChunks(
      buildApiUrl(nextPage),
      state.currentPage,
      { category, search, sortBy, sortOrder },
      2
    );
  }, [preloadNext, enableChunking, state.currentPage, buildApiUrl, category, search, sortBy, sortOrder]);

  // Refresh data
  const refresh = useCallback(async () => {
    // Clear cache for this query
    const pattern = `products:*${category || ''}*${search || ''}*`;
    cacheHelpers.invalidatePattern(pattern);
    
    // Clear chunks
    if (enableChunking && chunkManagerRef.current) {
      chunkManagerRef.current.clearChunks(buildApiUrl(1));
    }
    
    setState(prev => ({ ...prev, currentPage: 0, products: [] }));
    await fetchProducts(1, false);
  }, [category, search, enableChunking, buildApiUrl, fetchProducts]);

  // Reset state
  const reset = useCallback(() => {
    // Cancel any pending requests
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }
    
    setState({
      products: [],
      loading: false,
      error: null,
      hasMore: true,
      currentPage: 0,
      totalPages: 0,
      totalCount: 0,
      cacheHit: false,
    });
  }, []);

  // Get performance stats
  const getStats = useCallback(() => {
    const cacheStats = redisCache.info();
    const chunkStats = chunkManagerRef.current?.getStats() || {};
    
    return {
      cache: cacheStats,
      chunks: chunkStats,
      memory: `${((cacheStats.totalMemory || 0) / (1024 * 1024)).toFixed(2)} MB`,
    };
  }, []);

  // Initial load
  useEffect(() => {
    reset();
    fetchProducts(1, false);
    
    return () => {
      if (abortControllerRef.current) {
        abortControllerRef.current.abort();
      }
      if (enableChunking && chunkManagerRef.current) {
        chunkManagerRef.current.cancelAllRequests();
      }
    };
  }, [category, search, sortBy, sortOrder, limit, enableChunking, fetchProducts, reset]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (abortControllerRef.current) {
        abortControllerRef.current.abort();
      }
      if (enableChunking && chunkManagerRef.current) {
        chunkManagerRef.current.cancelAllRequests();
      }
    };
  }, [enableChunking]);

  return [
    state,
    {
      loadMore,
      refresh,
      reset,
      loadPage,
      preloadNextPage,
      getStats,
    },
  ];
}

/**
 * Hook for infinite scrolling with enhanced caching
 */
export function useInfiniteProducts(options: UseProductsOptions = {}) {
  const [state, actions] = useEnhancedProducts({
    ...options,
    enableChunking: true,
    preloadNext: true,
  });

  // Auto-load more when scrolling near bottom
  useEffect(() => {
    const handleScroll = () => {
      if (
        window.innerHeight + document.documentElement.scrollTop
        >= document.documentElement.offsetHeight - 1000 // 1000px before bottom
      ) {
        if (!state.loading && state.hasMore) {
          actions.loadMore();
        }
      }
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [state.loading, state.hasMore, actions]);

  return [state, actions] as const;
}

export default useEnhancedProducts;