/**
 * Utilities for face detection and location parsing
 */

export interface FaceLocation {
  x: number;
  y: number;
  width: number;
  height: number;
}

/**
 * Parses face location string from database
 * Supports multiple formats:
 * - JSON object: {"x": 100, "y": 200, "width": 150, "height": 150}
 * - JSON array: [100, 200, 150, 150] or [x1, y1, x2, y2]
 * - Comma-separated: "100,200,150,150" (x,y,width,height or x1,y1,x2,y2)
 */
export function parseFaceLocation(location: string): FaceLocation | null {
  if (!location) return null;

  // If location is already an object (shouldn't happen but handle it)
  if (typeof location === 'object' && location !== null) {
    const loc = location as any;
    if (typeof loc.x === 'number' && typeof loc.y === 'number' && 
        typeof loc.width === 'number' && typeof loc.height === 'number') {
      return { x: loc.x, y: loc.y, width: loc.width, height: loc.height };
    }
  }

  // If it's not a string, try to convert
  const locationStr = String(location).trim();
  if (!locationStr) return null;

  try {
    // Try JSON format first (object or array)
    const parsed = JSON.parse(locationStr);
    
    // Handle JSON object: {"x": 100, "y": 200, "width": 150, "height": 150}
    // or {"x": 100, "y": 200, "w": 150, "h": 150}
    if (typeof parsed === 'object' && parsed !== null) {
      // Handle width/height format
      if (
        typeof parsed.x === 'number' &&
        typeof parsed.y === 'number' &&
        typeof parsed.width === 'number' &&
        typeof parsed.height === 'number'
      ) {
        return {
          x: parsed.x,
          y: parsed.y,
          width: parsed.width,
          height: parsed.height,
        };
      }
      
      // Handle w/h format (shorthand)
      if (
        typeof parsed.x === 'number' &&
        typeof parsed.y === 'number' &&
        typeof parsed.w === 'number' &&
        typeof parsed.h === 'number'
      ) {
        return {
          x: parsed.x,
          y: parsed.y,
          width: parsed.w,
          height: parsed.h,
        };
      }
      
      // Handle object with x1, y1, x2, y2 format
      if (
        typeof parsed.x1 === 'number' &&
        typeof parsed.y1 === 'number' &&
        typeof parsed.x2 === 'number' &&
        typeof parsed.y2 === 'number'
      ) {
        return {
          x: parsed.x1,
          y: parsed.y1,
          width: parsed.x2 - parsed.x1,
          height: parsed.y2 - parsed.y1,
        };
      }
    }
    
    // Handle JSON array: [x, y, width, height] or [x1, y1, x2, y2]
    if (Array.isArray(parsed) && parsed.length === 4) {
      const [a, b, c, d] = parsed.map(Number);
      if (parsed.every((n: any) => typeof n === 'number' && !isNaN(n))) {
        // Check if it's x1,y1,x2,y2 format (width/height would be negative if x2<x1 or y2<y1)
        // Or if values suggest it's coordinates rather than size
        if (c > a && d > b) {
          // Likely x1, y1, x2, y2 format
          return {
            x: a,
            y: b,
            width: c - a,
            height: d - b,
          };
        } else {
          // Likely x, y, width, height format
          return {
            x: a,
            y: b,
            width: c,
            height: d,
          };
        }
      }
    }
  } catch {
    // Not JSON, try comma-separated format
  }

  // Try comma-separated format: "x,y,width,height" or "x1,y1,x2,y2"
  const parts = locationStr.split(',').map((s) => s.trim()).map(Number);
  if (parts.length === 4 && parts.every((n) => !isNaN(n))) {
    const [a, b, c, d] = parts;
    // Check if it's x1,y1,x2,y2 format (width/height would be negative if x2<x1 or y2<y1)
    if (c > a && d > b) {
      // Likely x1, y1, x2, y2 format
      return {
        x: a,
        y: b,
        width: c - a,
        height: d - b,
      };
    } else {
      // Likely x, y, width, height format
      return {
        x: a,
        y: b,
        width: c,
        height: d,
      };
    }
  }

  return null;
}

/**
 * Checks if a mouse point is within a face bounding box
 * Handles image scaling (object-fit: cover) correctly
 */
export function isPointInFace(
  mouseX: number,
  mouseY: number,
  faceLocation: FaceLocation,
  imageNaturalWidth: number,
  imageNaturalHeight: number,
  containerWidth: number,
  containerHeight: number
): boolean {
  return isPointInFaceWithFit(
    mouseX,
    mouseY,
    faceLocation,
    imageNaturalWidth,
    imageNaturalHeight,
    containerWidth,
    containerHeight,
    'cover'
  );
}

/**
 * Checks if a mouse point is within a face bounding box
 * Handles both object-fit: cover and object-fit: contain
 */
export function isPointInFaceWithFit(
  mouseX: number,
  mouseY: number,
  faceLocation: FaceLocation,
  imageNaturalWidth: number,
  imageNaturalHeight: number,
  containerWidth: number,
  containerHeight: number,
  objectFit: 'cover' | 'contain' = 'cover'
): boolean {
  if (!imageNaturalWidth || !imageNaturalHeight) return false;

  const imageAspect = imageNaturalWidth / imageNaturalHeight;
  const containerAspect = containerWidth / containerHeight;

  let scale: number;
  let offsetX = 0;
  let offsetY = 0;

  if (objectFit === 'cover') {
    // object-fit: cover - image covers entire container, may be cropped
    if (imageAspect > containerAspect) {
      // Image is wider - scale based on height
      scale = containerHeight / imageNaturalHeight;
      const scaledWidth = imageNaturalWidth * scale;
      offsetX = (containerWidth - scaledWidth) / 2;
    } else {
      // Image is taller - scale based on width
      scale = containerWidth / imageNaturalWidth;
      const scaledHeight = imageNaturalHeight * scale;
      offsetY = (containerHeight - scaledHeight) / 2;
    }
  } else {
    // object-fit: contain - image fits entirely within container, may have empty space
    if (imageAspect > containerAspect) {
      // Image is wider - scale based on width
      scale = containerWidth / imageNaturalWidth;
      const scaledHeight = imageNaturalHeight * scale;
      offsetY = (containerHeight - scaledHeight) / 2;
    } else {
      // Image is taller - scale based on height
      scale = containerHeight / imageNaturalHeight;
      const scaledWidth = imageNaturalWidth * scale;
      offsetX = (containerWidth - scaledWidth) / 2;
    }
  }

  // Scale face location to container coordinates
  const scaledX = faceLocation.x * scale + offsetX;
  const scaledY = faceLocation.y * scale + offsetY;
  const scaledWidth = faceLocation.width * scale;
  const scaledHeight = faceLocation.height * scale;

  // Check if mouse is within face bounds
  return (
    mouseX >= scaledX &&
    mouseX <= scaledX + scaledWidth &&
    mouseY >= scaledY &&
    mouseY <= scaledY + scaledHeight
  );
}

