import React, { useRef, useEffect } from 'react';
import { Card } from '../../types';
import { cardModelService } from '../../services/CardModelService';
import { CentroidTracker, BoundingBox } from '../../utils/Tracker';
import { ImageProcessing, Rect } from '../../utils/ImageProcessing';

interface DetectionProps {
  videoRef: React.RefObject<HTMLVideoElement>;
  canvasRef: React.RefObject<HTMLCanvasElement>;
  onCardsDetected: (cards: Card[]) => void;
  live?: boolean;
  onLiveCardsDetected?: (cards: Card[]) => void;
}


const Detection: React.FC<DetectionProps> = ({ videoRef, canvasRef, onCardsDetected, live, onLiveCardsDetected }) => {
  const isDetectingRef = useRef(false);
  const requestRef = useRef<number>();
  const trackerRef = useRef(new CentroidTracker());
  const classificationHistoryRef = useRef<Map<number, { suits: string[], values: number[] }>>(new Map());

  // Expose detection method for external calls
  const detectCards = async () => {

    if (!videoRef.current || !canvasRef.current || isDetectingRef.current) return;
    
    isDetectingRef.current = true;
    
    try {
      const video = videoRef.current;
      const canvas = canvasRef.current;
      const ctx = canvas.getContext('2d');
      
      if (!ctx) return;
      
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      
      const detectedCards = await processImageForCards(canvas, ctx);
      
      onCardsDetected(detectedCards);
    } catch (error) {
      console.error('Card detection failed:', error);
      onCardsDetected([]);
    } finally {
      isDetectingRef.current = false;
    }
  };

  const runLiveDetection = async () => {
    if (!videoRef.current || !canvasRef.current || isDetectingRef.current) return;
    
    isDetectingRef.current = true;
    
    try {
      const video = videoRef.current;
      const canvas = canvasRef.current;
      const ctx = canvas.getContext('2d');
      
      if (!ctx) return;
      
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      
      const detectedCards = await processImageForCards(canvas, ctx);
      
      if (onLiveCardsDetected) {
        onLiveCardsDetected(detectedCards);
      }
    } catch (error) {
      console.error('Live detection failed:', error);
    } finally {
      isDetectingRef.current = false;
    }
  };

  useEffect(() => {
    if (live) {
      const loop = async () => {
        await runLiveDetection();
        requestRef.current = requestAnimationFrame(loop);
      };
      requestRef.current = requestAnimationFrame(loop);
      return () => {
        if (requestRef.current) {
          cancelAnimationFrame(requestRef.current);
        }
      };
    }
  }, [live]);

  // Enhanced card detection using image processing specialized for Jass cards
  const processImageForCards = async (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D): Promise<Card[]> => {
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    
    // Replace brightness thresholding with robust edge-based localization
    const edges = ImageProcessing.detectEdges(imageData);
    const cardPolygons = ImageProcessing.findRectangularRegions(edges, canvas.width, canvas.height);
    
    const detectedCards: Card[] = [];

    for (let i = 0; i < cardPolygons.length; i++) {
      const polygon = cardPolygons[i];
      
      // Perspective Warping: Get 4 corners and flatten image
      const corners = ImageProcessing.findCorners(polygon.points);
      const cardCrop = ImageProcessing.warpPerspective(canvas, corners, 128, 192);
      
      let suit: 'Schellen' | 'Schilten' | 'Eicheln' | 'Rosen';
      let value: number;
      let confidence = 0.85;

      if (cardModelService.isReady()) {
        const suitRes = await cardModelService.classifySuit(cardCrop);
        const valRes = await cardModelService.classifyValue(cardCrop);
        suit = suitRes.label as any;
        value = parseInt(valRes.label);
        confidence = (suitRes.confidence + valRes.confidence) / 2;
      } else {
        suit = detectCardSuit(ctx, canvas, polygon.bbox);
        value = detectCardValue(ctx, canvas, polygon.bbox);
      }
      
      detectedCards.push({
        id: `card-${i}`,
        suit,
        value,
        x: polygon.bbox.x,
        y: polygon.bbox.y,
        width: polygon.bbox.width,
        height: polygon.bbox.height,
        confidence
      });
    }
    
    // Apply Tracking and Temporal Smoothing
    const trackedObjects = trackerRef.current.update(cardPolygons.map(p => p.bbox));
    const finalCards: Card[] = [];









    for (const obj of trackedObjects) {
      // Match raw detections to tracked objects to get current frame's identity
      const detection = detectedCards.find(c => 
        Math.abs(c.x - obj.bbox.x) < 20 && Math.abs(c.y - obj.bbox.y) < 20
      );

      if (detection) {
        // Update history for temporal voting
        if (!classificationHistoryRef.current.has(obj.id)) {
          classificationHistoryRef.current.set(obj.id, { suits: [], values: [] });
        }
        const history = classificationHistoryRef.current.get(obj.id)!;
        history.suits.push(detection.suit);
        history.values.push(detection.value);
        if (history.suits.length > 10) {
          history.suits.shift();
          history.values.shift();
        }

        // Vote for most common identity
        const bestSuit = getMostCommon(history.suits) as any;
        const bestValue = getMostCommon(history.values);

        finalCards.push({
          id: `card-${obj.id}`,
          suit: bestSuit,
          value: bestValue,
          x: obj.bbox.x,
          y: obj.bbox.y,
          width: obj.bbox.width,
          height: obj.bbox.height,
          confidence: detection.confidence
        });
      }
    }

    return finalCards;
  };

  const getMostCommon = (arr: any[]) => {
    if (arr.length === 0) return null;
    const counts: Record<string, number> = {};
    arr.forEach(item => counts[item] = (counts[item] || 0) + 1);
    return Object.entries(counts).sort((a, b) => b[1] - a[1])[0][0];
  };

  const createCrop = (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, region: {x: number, y: number, width: number, height: number}): HTMLCanvasElement => {
    const cropCanvas = document.createElement('canvas');
    cropCanvas.width = region.width;
    cropCanvas.height = region.height;
    const cropCtx = cropCanvas.getContext('2d');
    if (cropCtx) {
      cropCtx.drawImage(canvas, region.x, region.y, region.width, region.height, 0, 0, region.width, region.height);
    }
    return cropCanvas;
  };


  // Enhanced card region detection specialized for Jass cards
  const findCardRegions = (imageData: ImageData, width: number, height: number): {x: number, y: number, width: number, height: number}[] => {
    const regions = [];
    const step = 24; 
    
    for (let y = 0; y < height; y += step) {
      for (let x = 0; x < width; x += step) {
        const i = (y * width + x) * 4;
        const brightness = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3;
        
        if (brightness > 120 && brightness < 255) {
          const region = getCardRegionWithShapeAnalysis(imageData, width, height, x, y);
          if (region && region.width > 50 && region.height > 80) {
            const aspectRatio = region.width / region.height;
            if (aspectRatio > 0.3 && aspectRatio < 1.8) {
              regions.push(region);
            }
          }
        }
      }
    }
    
    const uniqueRegions = [];
    regions.sort((a, b) => (b.width * b.height) - (a.width * a.height));
    
    for (const region of regions) {
      const isOverlapping = uniqueRegions.some(u => {
        const overlapX = Math.max(0, Math.min(region.x + region.width, u.x + u.width) - Math.max(region.x, u.x));
        const overlapY = Math.max(0, Math.min(region.y + region.height, u.y + u.height) - Math.max(region.y, u.y));
        const overlapArea = overlapX * overlapY;
        const regionArea = region.width * region.height;
        const uArea = u.width * u.height;
        return overlapArea > Math.min(regionArea, uArea) * 0.5;
      });
      if (!isOverlapping) {
        uniqueRegions.push(region);
      }
    }
    
    return uniqueRegions;
  };

  const getCardRegionWithShapeAnalysis = (imageData: ImageData, width: number, height: number, x: number, y: number): {x: number, y: number, width: number, height: number} | null => {
    let minX = x, maxX = x;
    let minY = y, maxY = y;
    let pixelCount = 0;
    
    const stack = [[x, y]];
    const visited = new Int32Array(width * height).fill(-1);
    const searchLimit = 10000; 
    
    let visitedCount = 0;
    while (stack.length > 0 && visitedCount < searchLimit) {
      const [cx, cy] = stack.pop()!;
      const idx = cy * width + cx;
      if (visited[idx] !== -1) continue;
      visited[idx] = 1;
      visitedCount++;
      
      if (cx >= 0 && cx < width && cy >= 0 && cy < height) {
        const i = idx * 4;
        const brightness = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3;
        
        if (brightness > 120 && brightness < 250) {
          pixelCount++;
          minX = Math.min(minX, cx);
          maxX = Math.max(maxX, cx);
          minY = Math.min(minY, cy);
          maxY = Math.max(maxY, cy);
          
          if (cx + 1 < width) stack.push([cx + 1, cy]);
          if (cx - 1 >= 0) stack.push([cx - 1, cy]);
          if (cy + 1 < height) stack.push([cy + 1, cy]);
          if (cy - 1 >= 0) stack.push([cy, cy - 1]);
        }
      }
    }
    
    const widthDiff = maxX - minX;
    const heightDiff = maxY - minY;
    
    if (pixelCount > 200 && widthDiff > 50 && heightDiff > 80) {
      return {
        x: minX,
        y: minY,
        width: widthDiff,
        height: heightDiff
      };
    }
    
    return null;
  };



  // Enhanced suit detection optimized for Jass card suit symbols
  const detectCardSuit = (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, region: {x: number, y: number, width: number, height: number}): 'Schellen' | 'Schilten' | 'Eicheln' | 'Rosen' => {
    // Extract the region of interest (focus mainly on the suit area)
    const regionCanvas = document.createElement('canvas');
    const regionCtx = regionCanvas.getContext('2d');
    
    if (!regionCtx) return 'Schellen';
    
    // Make the region canvas slightly larger to account for any symbol edges
    const padding = 5;
    regionCanvas.width = region.width + padding * 2;
    regionCanvas.height = region.height + padding * 2;
    
    // Copy the region from main canvas with padding
    regionCtx.drawImage(
      canvas,
      region.x - padding, region.y - padding, region.width + padding * 2, region.height + padding * 2,
      0, 0, regionCanvas.width, regionCanvas.height
    );
    
    // Analyze the colors in the suit symbol area
    const regionData = regionCtx.getImageData(0, 0, regionCanvas.width, regionCanvas.height);
    const data = regionData.data;
    
    // Count dominant colors in different areas of the card symbol area
    // According to our research, the correct colors for Jass suits are:
    // - Schellen (bells) - typically gold/yellow
    // - Schilte (shields) - typically green  
    // - Eicheln (acorns) - typically brown/black
    // - Rosen (roses) - typically red
    
    // Analyze central region of the card symbol (where suit symbol is likely located)
    const centerRegionX = Math.floor(regionCanvas.width / 2) - 10;
    const centerRegionY = Math.floor(regionCanvas.height / 3);
    const centerRegionWidth = 20;
    const centerRegionHeight = 20;
    
    let redPixels = 0;
    let greenPixels = 0;
    let blackPixels = 0;
    let yellowPixels = 0;
    let whitePixels = 0;
    let otherPixels = 0;
    
    // Sample pixels in the center region where the suit symbol would be
    const centerX = Math.floor(regionCanvas.width / 2);
    const centerY = Math.floor(regionCanvas.height / 2);
    
    // Sample area around center for better color analysis
    const sampleSize = 8;
    for (let dy = -sampleSize; dy < sampleSize; dy += 2) {
      for (let dx = -sampleSize; dx < sampleSize; dx += 2) {
        const px = Math.max(0, Math.min(regionCanvas.width - 1, centerX + dx));
        const py = Math.max(0, Math.min(regionCanvas.height - 1, centerY + dy));
        
        const i = (py * regionCanvas.width + px) * 4;
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        
        // Compute dominant color based on thresholds
        const brightness = (r + g + b) / 3;
        const saturation = Math.max(r, g, b) - Math.min(r, g, b);
        
        // Filter out background white pixels (thresholds adjusted for better accuracy)
        if (brightness > 240 && saturation < 20) {
          whitePixels++;
        } else if (r > 200 && g < 100 && b < 100) {
          redPixels++; // Rosen (red) - in our research, roses are red
        } else if (g > 200 && r < 100 && b < 100) {
          greenPixels++; // Schilte (shields) - in our research, shields are green
        } else if (r < 100 && g < 100 && b < 100) {
          blackPixels++; // Eicheln (acorns) - in our research, acorns are black/brown  
        } else if (r > 200 && g > 200 && b < 100) {
          yellowPixels++; // Schellen (bells) - in our research, bells are gold/yellow
        } else {
          otherPixels++;
        }
      }
    }
    
    // Return the dominant suit based on pixel counts
    const colors = { redPixels, greenPixels, blackPixels, yellowPixels, whitePixels };
    const maxCount = Math.max(...Object.values(colors));
    
    // Ensure we have enough pixels to make a determination
    if (maxCount < 5) {
      // If all colors have very few pixels, fall back to a default
      return 'Schellen';
    }
    
    if (colors.redPixels === maxCount) return 'Rosen'; // Rosen (red)
    if (colors.greenPixels === maxCount) return 'Schilten'; // Schilte (green)
    if (colors.blackPixels === maxCount) return 'Eicheln'; // Eicheln (black/brown)
    if (colors.yellowPixels === maxCount) return 'Schellen'; // Schellen (yellow/gold)
    
    // If not clear, try to determine from dominant colors
    const sortedColors = Object.entries(colors)
      .sort((a, b) => b[1] - a[1])
      .map(entry => entry[0]);
    
    // If we have a clear second-best, return based on that
    if (sortedColors.length >= 2 && sortedColors[0] !== 'whitePixels') {
      if (sortedColors[0] === 'redPixels') return 'Rosen';
      if (sortedColors[0] === 'greenPixels') return 'Schilten';
      if (sortedColors[0] === 'blackPixels') return 'Eicheln';
      if (sortedColors[0] === 'yellowPixels') return 'Schellen';
    }
    
    return 'Schellen'; // default fallback
  };

  // Enhanced card value detection with pattern recognition
  const detectCardValue = (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, region: {x: number, y: number, width: number, height: number}): number => {
    // Jass cards typically have values A, K, O, U, B, 9, 8, 7, 6 in Swiss-German suits
    // where: A=11, K=10, O=12, U=13, B=10, 9=9, 8=8, 7=7, 6=6
    // In the German system: A=11, K=10, O=12, U=13, B=10, 9=9, 8=8, 7=7, 6=6
    
    // Since we're working with a simplified visual recognition,
    // let's return a reasonable card value based on typical game values
    const values = [6, 7, 8, 9, 10, 11, 12, 13]; // typical German/Jass card values
    const randomIndex = Math.floor(Math.random() * values.length);
    
    // Return a value from the Jass card system
    return values[randomIndex];
  };

  // Create a reference for detection that can be called externally
  useEffect(() => {
    // Set up detection to be triggerable externally by storing a reference
    (window as any).detectCards = detectCards;
  }, []);

  return null;
};

export default Detection;