import { useState, useCallback, useEffect, useRef } from 'react'
import axios from 'axios'
import { toast } from 'sonner'

/**
 * Custom hook for managing product lines and sublines fetching with caching
 */
export const useProductLinesFetching = (data: Record<string, any>[]) => {
  // State for tracking product lines and sublines per row
  const [rowProductLines, setRowProductLines] = useState<Record<string, any[]>>({});
  const [rowSublines, setRowSublines] = useState<Record<string, any[]>>({});
  
  // State for tracking loading states
  const [isLoadingLines, setIsLoadingLines] = useState<Record<string, boolean>>({});
  const [isLoadingSublines, setIsLoadingSublines] = useState<Record<string, boolean>>({});
  
  // Add caches for product lines and sublines by company/line ID
  const [companyLinesCache, setCompanyLinesCache] = useState<Record<string, any[]>>({});
  const [lineSublineCache, setLineSublineCache] = useState<Record<string, any[]>>({});
  
  // Track in-flight requests to prevent duplicate fetches (especially in StrictMode/dev)
  const pendingCompanyRequests = useRef<Set<string>>(new Set());
  const pendingLineRequests = useRef<Set<string>>(new Set());
  
  // Function to fetch product lines for a specific company - memoized
  const fetchProductLines = useCallback(async (rowIndex: string | number | undefined | null, companyId: string) => {
    try {
      // Only fetch if we have a valid company ID
      if (!companyId) return;
      
      const logRowKey = (rowIndex !== undefined && rowIndex !== null) ? rowIndex : 'all-matching-rows';
      console.log(`Fetching product lines for row ${logRowKey}, company ${companyId}`);
      
      // Check if we already have this company's lines in the cache
      if (companyLinesCache[companyId]) {
        console.log(`Using cached product lines for company ${companyId}`);
        // Use cached data
        const cached = companyLinesCache[companyId];
        // Update the specific row if provided
        if (rowIndex !== undefined && rowIndex !== null) {
          setRowProductLines(prev => ({ ...prev, [rowIndex]: cached }));
        }
        // Also update all rows that currently have this company set
        const updates: Record<string, any[]> = {};
        data.forEach((row, idx) => {
          if (row.company && String(row.company) === String(companyId)) {
            const key = (row.__index !== undefined && row.__index !== null) ? row.__index : idx;
            updates[key] = cached;
          }
        });
        if (Object.keys(updates).length > 0) {
          setRowProductLines(prev => ({ ...prev, ...updates }));
        }
        return cached;
      }

      // If a request for this company is already in flight, skip duplicate fetch
      if (pendingCompanyRequests.current.has(companyId)) {
        console.log(`Skipping fetch for company ${companyId} - request already pending`);
        return;
      }
      pendingCompanyRequests.current.add(companyId);
      
      // Set loading state for this row
      if (rowIndex !== undefined && rowIndex !== null) {
        setIsLoadingLines(prev => ({ ...prev, [rowIndex]: true }));
      }
      
      // Fetch product lines from API
      const productLinesUrl = `/api/import/product-lines/${companyId}`;
      const response = await axios.get(productLinesUrl);
      
      const lines = response.data;
      console.log(`Received ${lines.length} product lines for company ${companyId}`);
      
      // Format the data properly for dropdown display
      const formattedLines = lines.map((line: any) => ({
        label: line.name || line.label || String(line.value || line.id),
        value: String(line.value || line.id)
      }));
      
      // Store in company cache
      setCompanyLinesCache(prev => ({ ...prev, [companyId]: formattedLines }));
      
      // Update specific row if provided
      if (rowIndex !== undefined && rowIndex !== null) {
        setRowProductLines(prev => ({ ...prev, [rowIndex]: formattedLines }));
      }
      
      // Also update all rows that currently have this company set
      const updates: Record<string, any[]> = {};
      data.forEach((row, idx) => {
        if (row.company && String(row.company) === String(companyId)) {
          const key = (row.__index !== undefined && row.__index !== null) ? row.__index : idx;
          updates[key] = formattedLines;
        }
      });
      if (Object.keys(updates).length > 0) {
        setRowProductLines(prev => ({ ...prev, ...updates }));
      }
      
      return formattedLines;
    } catch (error) {
      console.error(`Error fetching product lines for company ${companyId}:`, error);
      toast.error(`Failed to load product lines for company ${companyId}`);
      
      // Set empty array for this company to prevent repeated failed requests
      setCompanyLinesCache(prev => ({ ...prev, [companyId]: [] }));
      
      // Store empty array for this specific row
      if (rowIndex !== undefined && rowIndex !== null) {
        setRowProductLines(prev => ({ ...prev, [rowIndex]: [] }));
      }
      
      return [];
    } finally {
      // Clear pending flag
      pendingCompanyRequests.current.delete(companyId);
      // Clear loading state
      if (rowIndex !== undefined && rowIndex !== null) {
        setIsLoadingLines(prev => ({ ...prev, [rowIndex]: false }));
      }
    }
  }, [companyLinesCache, data]);
  
  // Function to fetch sublines for a specific line - memoized
  const fetchSublines = useCallback(async (rowIndex: string | number | undefined | null, lineId: string) => {
    try {
      // Only fetch if we have a valid line ID
      if (!lineId) return;
      
      const logRowKey = (rowIndex !== undefined && rowIndex !== null) ? rowIndex : 'all-matching-rows';
      console.log(`Fetching sublines for row ${logRowKey}, line ${lineId}`);
      
      // Check if we already have this line's sublines in the cache
      if (lineSublineCache[lineId]) {
        console.log(`Using cached sublines for line ${lineId}`);
        // Use cached data
        const cached = lineSublineCache[lineId];
        if (rowIndex !== undefined && rowIndex !== null) {
          setRowSublines(prev => ({ ...prev, [rowIndex]: cached }));
        }
        // Also update all rows with this line
        const updates: Record<string, any[]> = {};
        data.forEach((row, idx) => {
          if (row.line && String(row.line) === String(lineId)) {
            const key = (row.__index !== undefined && row.__index !== null) ? row.__index : idx;
            updates[key] = cached;
          }
        });
        if (Object.keys(updates).length > 0) {
          setRowSublines(prev => ({ ...prev, ...updates }));
        }
        return cached;
      }

      // If a request for this line is already in flight, skip duplicate fetch
      if (pendingLineRequests.current.has(lineId)) {
        console.log(`Skipping fetch for line ${lineId} - request already pending`);
        return;
      }
      pendingLineRequests.current.add(lineId);
      
      // Set loading state for this row
      if (rowIndex !== undefined && rowIndex !== null) {
        setIsLoadingSublines(prev => ({ ...prev, [rowIndex]: true }));
      }
      
      // Fetch sublines from API
      const sublinesUrl = `/api/import/sublines/${lineId}`;
      const response = await axios.get(sublinesUrl);
      
      const sublines = response.data;
      console.log(`Received ${sublines.length} sublines for line ${lineId}`);
      
      // Format the data properly for dropdown display
      const formattedSublines = sublines.map((subline: any) => ({
        label: subline.name || subline.label || String(subline.value || subline.id),
        value: String(subline.value || subline.id)
      }));
      
      // Store in line cache
      setLineSublineCache(prev => ({ ...prev, [lineId]: formattedSublines }));
      
      // Update specific row if provided
      if (rowIndex !== undefined && rowIndex !== null) {
        setRowSublines(prev => ({ ...prev, [rowIndex]: formattedSublines }));
      }
      
      // Also update all rows with this line
      const updates: Record<string, any[]> = {};
      data.forEach((row, idx) => {
        if (row.line && String(row.line) === String(lineId)) {
          const key = (row.__index !== undefined && row.__index !== null) ? row.__index : idx;
          updates[key] = formattedSublines;
        }
      });
      if (Object.keys(updates).length > 0) {
        setRowSublines(prev => ({ ...prev, ...updates }));
      }
      
      return formattedSublines;
    } catch (error) {
      console.error(`Error fetching sublines for line ${lineId}:`, error);
      
      // Set empty array for this line to prevent repeated failed requests
      setLineSublineCache(prev => ({ ...prev, [lineId]: [] }));
      
      // Store empty array for this specific row
      if (rowIndex !== undefined && rowIndex !== null) {
        setRowSublines(prev => ({ ...prev, [rowIndex]: [] }));
      }
      
      return [];
    } finally {
      // Clear pending flag
      pendingLineRequests.current.delete(lineId);
      // Clear loading state
      if (rowIndex !== undefined && rowIndex !== null) {
        setIsLoadingSublines(prev => ({ ...prev, [rowIndex]: false }));
      }
    }
  }, [lineSublineCache, data]);
  
  // When data changes, fetch product lines and sublines for rows that have company/line values
  useEffect(() => {
    // Skip if there's no data
    if (!data.length) return;
    
    // First check if we need to do anything at all
    let needsFetching = false;
    
    // Quick check for any rows that would need fetching
    for (const row of data) {
      const rowId = row.__index;
      if (!rowId) continue;
      
      if ((row.company && !rowProductLines[rowId]) || (row.line && !rowSublines[rowId])) {
        needsFetching = true;
        break;
      }
    }
    
    // If nothing needs fetching, exit early
    if (!needsFetching) {
      return;
    }
    
    console.log("Starting to fetch product lines and sublines");
    
    // Group rows by company and line to minimize API calls
    const companiesNeeded = new Map<string, string[]>(); // company ID -> row IDs
    const linesNeeded = new Map<string, string[]>(); // line ID -> row IDs
    
    data.forEach(row => {
      const rowId = row.__index;
      if (!rowId) return; // Skip rows without an index
      
      // If row has company but no product lines fetched yet
      if (row.company && !rowProductLines[rowId]) {
        const companyId = row.company.toString();
        if (!companiesNeeded.has(companyId)) {
          companiesNeeded.set(companyId, []);
        }
        companiesNeeded.get(companyId)?.push(rowId);
      }
      
      // If row has line but no sublines fetched yet
      if (row.line && !rowSublines[rowId]) {
        const lineId = row.line.toString();
        if (!linesNeeded.has(lineId)) {
          linesNeeded.set(lineId, []);
        }
        linesNeeded.get(lineId)?.push(rowId);
      }
    });
    
    console.log(`Need to fetch product lines for ${companiesNeeded.size} companies and sublines for ${linesNeeded.size} lines`);
    
    // If nothing to fetch, exit early to prevent unnecessary processing
    if (companiesNeeded.size === 0 && linesNeeded.size === 0) {
      return;
    }
    
    // Create arrays to hold all fetch promises
    const fetchPromises: Promise<void>[] = [];
    
    // Set initial loading states for all affected rows
    const lineLoadingUpdates: Record<string, boolean> = {};
    const sublineLoadingUpdates: Record<string, boolean> = {};
    
    // Process companies that need product lines
    companiesNeeded.forEach((rowIds, companyId) => {
      // If this company is already being fetched, skip creating another request
      if (pendingCompanyRequests.current.has(companyId)) {
        console.log(`Skipping batch fetch for company ${companyId} - request already pending`);
        return;
      }
      // Skip if already in cache
      if (companyLinesCache[companyId]) {
        console.log(`Using cached product lines for company ${companyId}`);
        // Use cached data for all rows with this company
        const lines = companyLinesCache[companyId];
        const updates: Record<string, any[]> = {};
        rowIds.forEach(rowId => {
          updates[rowId] = lines;
        });
        setRowProductLines(prev => ({ ...prev, ...updates }));
        return;
      }
      
      // Set loading state for all affected rows
      rowIds.forEach(rowId => {
        lineLoadingUpdates[rowId] = true;
      });
      
      // Create fetch promise
      const fetchPromise = (async () => {
        // Mark this company as pending
        pendingCompanyRequests.current.add(companyId);
        // Safety timeout to ensure loading state is cleared after 10 seconds
        const timeoutId = setTimeout(() => {
          console.log(`Safety timeout triggered for company ${companyId}`);
          const clearLoadingUpdates: Record<string, boolean> = {};
          rowIds.forEach(rowId => {
            clearLoadingUpdates[rowId] = false;
          });
          setIsLoadingLines(prev => ({ ...prev, ...clearLoadingUpdates }));
          
          // Set empty cache to prevent repeated requests
          setCompanyLinesCache(prev => ({ ...prev, [companyId]: [] }));
          
          // Update rows with empty array
          const updates: Record<string, any[]> = {};
          rowIds.forEach(rowId => {
            updates[rowId] = [];
          });
          setRowProductLines(prev => ({ ...prev, ...updates }));
          
          toast.error(`Timeout loading product lines for company ${companyId}`);
        }, 10000);
        
        try {
          console.log(`Fetching product lines for company ${companyId} (affecting ${rowIds.length} rows)`);
          
          // Fetch product lines from API
          const productLinesUrl = `/api/import/product-lines/${companyId}`;
          console.log(`Fetching from URL: ${productLinesUrl}`);
          
          const response = await axios.get(productLinesUrl);
          console.log(`Product lines API response status for company ${companyId}:`, response.status);
          
          const productLines = response.data;
          console.log(`Received ${productLines.length} product lines for company ${companyId}`);
          
          // Format the data for dropdown display (consistent with single-row fetch)
          const formattedLines = productLines.map((line: any) => ({
            label: line.name || line.label || String(line.value || line.id),
            value: String(line.value || line.id)
          }));
          
          // Store in company cache
          setCompanyLinesCache(prev => ({ ...prev, [companyId]: formattedLines }));
          
          // Update all rows with this company
          const updates: Record<string, any[]> = {};
          rowIds.forEach(rowId => {
            updates[rowId] = formattedLines;
          });
          setRowProductLines(prev => ({ ...prev, ...updates }));
        } catch (error) {
          console.error(`Error fetching product lines for company ${companyId}:`, error);
          
          // Set empty array for this company to prevent repeated failed requests
          setCompanyLinesCache(prev => ({ ...prev, [companyId]: [] }));
          
          // Update rows with empty array
          const updates: Record<string, any[]> = {};
          rowIds.forEach(rowId => {
            updates[rowId] = [];
          });
          setRowProductLines(prev => ({ ...prev, ...updates }));
          
          // Show error toast
          toast.error(`Failed to load product lines for company ${companyId}`);
        } finally {
          // Clear pending flag for company
          pendingCompanyRequests.current.delete(companyId);
          // Clear the safety timeout
          clearTimeout(timeoutId);
          
          // Clear loading state for all affected rows
          const clearLoadingUpdates: Record<string, boolean> = {};
          rowIds.forEach(rowId => {
            clearLoadingUpdates[rowId] = false;
          });
          setIsLoadingLines(prev => ({ ...prev, ...clearLoadingUpdates }));
        }
      })();
      
      fetchPromises.push(fetchPromise);
    });
    
    // Process lines that need sublines
    linesNeeded.forEach((rowIds, lineId) => {
      // If this line is already being fetched, skip creating another request
      if (pendingLineRequests.current.has(lineId)) {
        console.log(`Skipping batch fetch for line ${lineId} - request already pending`);
        return;
      }
      // Skip if already in cache
      if (lineSublineCache[lineId]) {
        console.log(`Using cached sublines for line ${lineId}`);
        // Use cached data for all rows with this line
        const sublines = lineSublineCache[lineId];
        const updates: Record<string, any[]> = {};
        rowIds.forEach(rowId => {
          updates[rowId] = sublines;
        });
        setRowSublines(prev => ({ ...prev, ...updates }));
        return;
      }
      
      // Set loading state for all affected rows
      rowIds.forEach(rowId => {
        sublineLoadingUpdates[rowId] = true;
      });
      
      // Create fetch promise
      const fetchPromise = (async () => {
        // Mark this line as pending
        pendingLineRequests.current.add(lineId);
        // Safety timeout to ensure loading state is cleared after 10 seconds
        const timeoutId = setTimeout(() => {
          console.log(`Safety timeout triggered for line ${lineId}`);
          const clearLoadingUpdates: Record<string, boolean> = {};
          rowIds.forEach(rowId => {
            clearLoadingUpdates[rowId] = false;
          });
          setIsLoadingSublines(prev => ({ ...prev, ...clearLoadingUpdates }));
          
          // Set empty cache to prevent repeated requests
          setLineSublineCache(prev => ({ ...prev, [lineId]: [] }));
          
          // Update rows with empty array
          const updates: Record<string, any[]> = {};
          rowIds.forEach(rowId => {
            updates[rowId] = [];
          });
          setRowSublines(prev => ({ ...prev, ...updates }));
          
          toast.error(`Timeout loading sublines for line ${lineId}`);
        }, 10000);
        
        try {
          console.log(`Fetching sublines for line ${lineId} (affecting ${rowIds.length} rows)`);
          
          // Fetch sublines from API
          const sublinesUrl = `/api/import/sublines/${lineId}`;
          console.log(`Fetching from URL: ${sublinesUrl}`);
          
          const response = await axios.get(sublinesUrl);
          console.log(`Sublines API response status for line ${lineId}:`, response.status);
          
          const sublines = response.data;
          console.log(`Received ${sublines.length} sublines for line ${lineId}`);
          
          // Format the data for dropdown display (consistent with single-row fetch)
          const formattedSublines = sublines.map((subline: any) => ({
            label: subline.name || subline.label || String(subline.value || subline.id),
            value: String(subline.value || subline.id)
          }));
          
          // Store in line cache
          setLineSublineCache(prev => ({ ...prev, [lineId]: formattedSublines }));
          
          // Update all rows with this line
          const updates: Record<string, any[]> = {};
          rowIds.forEach(rowId => {
            updates[rowId] = formattedSublines;
          });
          setRowSublines(prev => ({ ...prev, ...updates }));
        } catch (error) {
          console.error(`Error fetching sublines for line ${lineId}:`, error);
          
          // Set empty array for this line to prevent repeated failed requests
          setLineSublineCache(prev => ({ ...prev, [lineId]: [] }));
          
          // Update rows with empty array
          const updates: Record<string, any[]> = {};
          rowIds.forEach(rowId => {
            updates[rowId] = [];
          });
          setRowSublines(prev => ({ ...prev, ...updates }));
          
          // Show error toast
          toast.error(`Failed to load sublines for line ${lineId}`);
        } finally {
          // Clear pending flag for line
          pendingLineRequests.current.delete(lineId);
          // Clear the safety timeout
          clearTimeout(timeoutId);
          
          // Clear loading state for all affected rows
          const clearLoadingUpdates: Record<string, boolean> = {};
          rowIds.forEach(rowId => {
            clearLoadingUpdates[rowId] = false;
          });
          setIsLoadingSublines(prev => ({ ...prev, ...clearLoadingUpdates }));
        }
      })();
      
      fetchPromises.push(fetchPromise);
    });
    
    // Set initial loading states
    if (Object.keys(lineLoadingUpdates).length > 0) {
      console.log(`Setting loading state for ${Object.keys(lineLoadingUpdates).length} rows (product lines)`);
      setIsLoadingLines(prev => ({ ...prev, ...lineLoadingUpdates }));
    }
    if (Object.keys(sublineLoadingUpdates).length > 0) {
      console.log(`Setting loading state for ${Object.keys(sublineLoadingUpdates).length} rows (sublines)`);
      setIsLoadingSublines(prev => ({ ...prev, ...sublineLoadingUpdates }));
    }
    
    // Run all fetch operations in parallel
    Promise.all(fetchPromises).then(() => {
      console.log("All product lines and sublines fetch operations completed");
    }).catch(error => {
      console.error('Error in fetch operations:', error);
    });
    
  }, [data, rowProductLines, rowSublines, companyLinesCache, lineSublineCache]);
  
  return {
    rowProductLines,
    rowSublines,
    isLoadingLines,
    isLoadingSublines,
    fetchProductLines,
    fetchSublines
  };
}; 
