import { toast } from "sonner";
import { apiFetch } from '@/utils/api';
import config from "@/config";
import { Product, ProductImageSortable, ImageMetadata, ImageNotice } from "../types";

const MIN_DIMENSION = 1000;
const MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;

const readImageMetadata = async (file: File): Promise<ImageMetadata> => {
  try {
    if (typeof createImageBitmap === "function") {
      const bitmap = await createImageBitmap(file);
      return {
        width: bitmap.width,
        height: bitmap.height,
        size: file.size
      };
    }
  } catch (error) {
    console.warn("createImageBitmap failed, falling back to Image element", error);
  }

  return new Promise((resolve) => {
    const image = new Image();
    const objectUrl = URL.createObjectURL(file);

    image.onload = () => {
      resolve({
        width: image.naturalWidth,
        height: image.naturalHeight,
        size: file.size
      });
      URL.revokeObjectURL(objectUrl);
    };

    image.onerror = () => {
      resolve({ size: file.size });
      URL.revokeObjectURL(objectUrl);
    };

    image.src = objectUrl;
  });
};

const analyzeImage = async (file: File) => {
  const metadata = await readImageMetadata(file);
  const notices: ImageNotice[] = [];

  if (metadata.width && metadata.height) {
    if (metadata.width < MIN_DIMENSION || metadata.height < MIN_DIMENSION) {
      notices.push({
        message: `Image is ${metadata.width}x${metadata.height}. Recommended minimum is ${MIN_DIMENSION}x${MIN_DIMENSION}.`,
        level: 'warning',
        code: 'dimensions_too_small',
        source: 'client'
      });
    }
  } else {
    notices.push({
      message: "Unable to verify image dimensions.",
      level: 'info',
      code: 'dimensions_unknown',
      source: 'client'
    });
  }

  if (file.size > MAX_FILE_SIZE_BYTES) {
    const sizeMb = (file.size / (1024 * 1024)).toFixed(1);
    notices.push({
      message: `Image is ${sizeMb}MB. Files above 5MB will be optimized automatically.`,
      level: 'info',
      code: 'client_large_file',
      source: 'client'
    });
  }

  return { metadata, notices };
};

const dedupeNotices = (notices: ImageNotice[] = []) => {
  const seen = new Set<string>();
  return notices.filter((notice) => {
    const key = `${notice.level}:${notice.code ?? ''}:${notice.message}`;
    if (seen.has(key)) {
      return false;
    }
    seen.add(key);
    return true;
  });
};

interface UseProductImageOperationsProps {
  data: Product[];
  productImages: ProductImageSortable[];
  setProductImages: React.Dispatch<React.SetStateAction<ProductImageSortable[]>>;
}

export const useProductImageOperations = ({
  data,
  productImages,
  setProductImages,
}: UseProductImageOperationsProps) => {
  // Function to remove an image URL from a product
  const removeImageFromProduct = (productIndex: number, imageUrl: string) => {
    // Create a copy of the data
    const newData = [...data];
    
    // Get the current product
    const product = newData[productIndex];
    
    // We need to update product_images array directly instead of the image_url field
    if (!product.product_images) {
      product.product_images = [];
    } else if (typeof product.product_images === 'string') {
      // Handle case where it might be a comma-separated string
      product.product_images = product.product_images.split(',').filter(Boolean);
    }
    
    // Filter out the image URL we're removing
    if (Array.isArray(product.product_images)) {
      product.product_images = product.product_images.filter((url: string) => url && url !== imageUrl);
    }
    
    return newData;
  };
  
  // Function to add an image URL to a product
  const addImageToProduct = (productIndex: number, imageUrl: string) => {
    // Create a copy of the data
    const newData = [...data];
    
    // Get the current product
    const product = newData[productIndex];
    
    // Initialize product_images array if it doesn't exist
    if (!product.product_images) {
      product.product_images = [];
    } else if (typeof product.product_images === 'string') {
      // Handle case where it might be a comma-separated string
      product.product_images = product.product_images.split(',').filter(Boolean);
    }
    
    // Ensure it's an array
    if (!Array.isArray(product.product_images)) {
      product.product_images = [product.product_images].filter(Boolean);
    }
    
    // Only add if the URL doesn't already exist (spread to avoid mutating frozen Immer arrays)
    if (!product.product_images.includes(imageUrl)) {
      product.product_images = [...product.product_images, imageUrl];
    }
    
    return newData;
  };

  // Function to handle image upload - update product data
  const handleImageUpload = async (files: FileList | File[], productIndex: number): Promise<{ uploaded: number; skipped: number }> => {
    if (!files || files.length === 0) return { uploaded: 0, skipped: 0 };

    let uploaded = 0;
    let skipped = 0;

    for (let i = 0; i < files.length; i++) {
      const file = files[i];

      // Check for exact duplicate (same filename, size, and type already uploaded for this product)
      const isDuplicate = productImages.some(
        img => img.productIndex === productIndex &&
               !img.loading &&
               img.imageUrl &&
               img.fileName === file.name &&
               img.metadata?.size === file.size
      );
      if (isDuplicate) {
        skipped++;
        continue;
      }

      const imageId = `image-${productIndex}-${Date.now()}-${i}`;
      const productLabel = data[productIndex].name || `Product #${productIndex + 1}`;
      
      // Add placeholder for this image
      const newImage: ProductImageSortable = {
        id: imageId,
        productIndex,
        imageUrl: '',
        loading: true,
        fileName: file.name,
        // Add required schema fields for ProductImageSortable
        pid: data[productIndex].id || 0,
        iid: 0,
        type: 0, 
        order: 0,
        width: 0,
        height: 0,
        hidden: 0
      };
      
      setProductImages(prev => [...prev, newImage]);

      let analysisNotices: ImageNotice[] | undefined;
      let metadata: ImageMetadata | undefined;

      try {
        const analysis = await analyzeImage(file);
        metadata = analysis.metadata;
        analysisNotices = analysis.notices?.length ? dedupeNotices(analysis.notices) : undefined;

        if (analysisNotices?.length) {
          const warningMessages = analysisNotices
            .filter((notice) => notice.level === 'warning')
            .map((notice) => notice.message);
          const infoMessages = analysisNotices
            .filter((notice) => notice.level === 'info')
            .map((notice) => notice.message);

          if (warningMessages.length) {
            toast.warning(`${file.name}: ${warningMessages.join(" ")}`);
          }

          if (infoMessages.length) {
            if (typeof toast.info === 'function') {
              toast.info(`${file.name}: ${infoMessages.join(" ")}`);
            } else {
              toast(`${file.name}`, {
                description: infoMessages.join(" "),
              });
            }
          }
        }

        setProductImages(prev =>
          prev.map(img =>
            img.id === imageId
              ? { ...img, metadata, notices: analysisNotices }
              : img
          )
        );
      } catch (error) {
        console.warn('Failed to analyze image before upload', error);
      }
      
      // Create form data for upload
      const formData = new FormData();
      formData.append('image', file);
      formData.append('productIndex', productIndex.toString());
      formData.append('upc', data[productIndex].upc || '');
      formData.append('supplier_no', data[productIndex].supplier_no || '');
      
      try {
        // Upload the image
        const response = await apiFetch(`${config.apiUrl}/import/upload-image`, {
          method: 'POST',
          body: formData,
        });
        
        if (!response.ok) {
          throw new Error('Failed to upload image');
        }
        
        const result = await response.json();
        const serverNotices: ImageNotice[] = Array.isArray(result.notices)
          ? result.notices.map((notice: any) => ({
              message: String(notice.message ?? notice),
              level: notice.level === 'warning' ? 'warning' : 'info',
              code: notice.code,
              source: notice.source ?? 'server'
            }))
          : Array.isArray(result.warnings)
            ? result.warnings.map((message: any) => ({
                message: String(message),
                level: 'info',
                source: 'server'
              }))
            : [];

        if (serverNotices.length) {
          const warningMessages = serverNotices
            .filter((notice) => notice.level === 'warning')
            .map((notice) => notice.message);
          const infoMessages = serverNotices
            .filter((notice) => notice.level === 'info')
            .map((notice) => notice.message);

          if (warningMessages.length) {
            toast.warning(`${file.name}: ${warningMessages.join(" ")}`);
          }

          if (infoMessages.length) {
            if (typeof toast.info === 'function') {
              toast.info(`${file.name}: ${infoMessages.join(" ")}`);
            } else {
              toast(`${file.name}`, {
                description: infoMessages.join(" "),
              });
            }
          }
        }
        
        // Update the image URL in our state
        setProductImages(prev => 
          prev.map(img => {
            if (img.id !== imageId) return img;

            const combinedNotices = dedupeNotices([
              ...(analysisNotices || []),
              ...serverNotices
            ]);

            const combinedMetadata: ImageMetadata | undefined = result.metadata
              ? { ...metadata, ...result.metadata }
              : metadata;

            return {
              ...img,
              imageUrl: result.imageUrl,
              loading: false,
              notices: combinedNotices.length ? combinedNotices : undefined,
              metadata: combinedMetadata,
            };
          })
        );
        
        // Update the product data with the new image URL
        addImageToProduct(productIndex, result.imageUrl);

        uploaded++;
        toast.success(`Image uploaded for ${productLabel}`);
      } catch (error) {
        console.error('Upload error:', error);

        // Remove the failed image from our state
        setProductImages(prev => prev.filter(img => img.id !== imageId));

        toast.error(`Failed to upload image: ${error instanceof Error ? error.message : 'Unknown error'}`);
      }
    }

    return { uploaded, skipped };
  };
  
  // Function to remove an image - update to work with product_images
  const removeImage = async (imageIndex: number) => {
    const image = productImages[imageIndex];
    if (!image) return;
    
    try {
      // Check if this is an external URL-based image or an uploaded image
      const isExternalUrl = image.imageUrl.startsWith('http') && 
        !image.imageUrl.includes(config.apiUrl.replace(/^https?:\/\//, ''));
      
      // Only call the API to delete the file if it's an uploaded image
      if (!isExternalUrl) {
        // Extract the filename from the URL
        const urlParts = image.imageUrl.split('/');
        const filename = urlParts[urlParts.length - 1];
        
        // Call API to delete the image
        const response = await apiFetch(`${config.apiUrl}/import/delete-image`, {
          method: 'DELETE',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({ 
            imageUrl: image.imageUrl,
            filename
          }),
        });
        
        if (!response.ok) {
          throw new Error('Failed to delete image');
        }
      }
      
      // Remove the image from our state
      setProductImages(prev => prev.filter((_, idx) => idx !== imageIndex));
      
      // Remove the image URL from the product data
      removeImageFromProduct(image.productIndex, image.imageUrl);
      
      toast.success('Image removed successfully');
    } catch (error) {
      console.error('Delete error:', error);
      toast.error(`Failed to remove image: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  };

  return {
    removeImageFromProduct,
    addImageToProduct,
    handleImageUpload,
    removeImage,
  };
}; 
