'use client';
import {
  Dropzone,
  DropZoneArea,
  DropzoneDescription,
  DropzoneFileListItem,
  DropzoneMessage,
  DropzoneRemoveFile,
  DropzoneTrigger,
  useDropzone
} from '@/components/ui/dropzone';
import { useGlobalContext } from '@/context/Provider';
import apis, { BUCKET_ROOT } from '@/utils/apis';
import { Trash2Icon, ImagePlus, Crop, ZoomIn, ZoomOut } from 'lucide-react';
import { useEffect, useState, useCallback, useRef } from 'react';
import Cropper from 'react-easy-crop';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';

// Helper to create a cropped image from canvas
async function getCroppedImg(imageSrc: string, pixelCrop: { x: number; y: number; width: number; height: number }): Promise<File> {
  const image = new Image();
  image.crossOrigin = 'anonymous';
  await new Promise<void>((resolve, reject) => {
    image.onload = () => resolve();
    image.onerror = reject;
    image.src = imageSrc;
  });

  const canvas = document.createElement('canvas');
  canvas.width = pixelCrop.width;
  canvas.height = pixelCrop.height;
  const ctx = canvas.getContext('2d')!;

  ctx.drawImage(
    image,
    pixelCrop.x,
    pixelCrop.y,
    pixelCrop.width,
    pixelCrop.height,
    0,
    0,
    pixelCrop.width,
    pixelCrop.height
  );

  return new Promise((resolve, reject) => {
    canvas.toBlob((blob) => {
      if (!blob) {
        reject(new Error('Canvas is empty'));
        return;
      }
      const file = new File([blob], `cropped-${Date.now()}.jpg`, { type: 'image/jpeg' });
      resolve(file);
    }, 'image/jpeg', 0.95);
  });
}

// Helper to read file as data URL
function readFileAsDataURL(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

export function MultiImages({ addImages, images }: { addImages: any, images?: any }) {
  const { Toast } = useGlobalContext();
  const [uploadedImages, setUploadedImages] = useState<any[]>([]);

  // Crop state
  const [cropModalOpen, setCropModalOpen] = useState(false);
  const [imageToCrop, setImageToCrop] = useState<string | null>(null);
  const [currentFileName, setCurrentFileName] = useState<string>('');
  const [crop, setCrop] = useState({ x: 0, y: 0 });
  const [zoom, setZoom] = useState(1);
  const [croppedAreaPixels, setCroppedAreaPixels] = useState<any>(null);
  const [isCropping, setIsCropping] = useState(false);

  // Queue state for handling multiple files
  const [queueInfo, setQueueInfo] = useState({ current: 0, total: 0 });
  const pendingResolve = useRef<((file: File | null) => void) | null>(null);

  // Queue for sequential processing
  const fileQueueRef = useRef<File[]>([]);
  const isProcessingRef = useRef(false);
  const queueResolversRef = useRef<Map<string, (result: any) => void>>(new Map());

  const onCropComplete = useCallback((_: any, croppedPixels: any) => {
    setCroppedAreaPixels(croppedPixels);
  }, []);

  const resetCropState = () => {
    setCropModalOpen(false);
    setImageToCrop(null);
    setCurrentFileName('');
    setCrop({ x: 0, y: 0 });
    setZoom(1);
    setCroppedAreaPixels(null);
    pendingResolve.current = null;
  };

  const handleCropConfirm = async () => {
    if (!imageToCrop || !croppedAreaPixels) return;
    setIsCropping(true);
    try {
      const croppedFile = await getCroppedImg(imageToCrop, croppedAreaPixels);
      const resolver = pendingResolve.current;
      resetCropState();
      setIsCropping(false);
      resolver?.(croppedFile);
    } catch (e) {
      Toast.error('Failed to crop image');
      const resolver = pendingResolve.current;
      resetCropState();
      setIsCropping(false);
      resolver?.(null);
    }
  };

  const handleSkipCrop = () => {
    // Upload original file without cropping — need to get the original file
    // We stored it via the queue, so we resolve with null to signal "use original"
    const resolver = pendingResolve.current;
    resetCropState();
    resolver?.(null); // null = signal to use original file
  };

  // Show crop modal for a single file and return a promise that resolves with the cropped file
  const showCropForFile = (file: File, currentIndex: number, totalFiles: number): Promise<File> => {
    return new Promise(async (resolve) => {
      try {
        const dataUrl = await readFileAsDataURL(file);
        setImageToCrop(dataUrl);
        setCurrentFileName(file.name);
        setQueueInfo({ current: currentIndex, total: totalFiles });
        setCrop({ x: 0, y: 0 });
        setZoom(1);
        setCroppedAreaPixels(null);
        setCropModalOpen(true);

        pendingResolve.current = (croppedFile: File | null) => {
          // If croppedFile is null, use the original file
          resolve(croppedFile || file);
        };
      } catch {
        // If reading fails, use original file
        resolve(file);
      }
    });
  };

  // Process the queue of files one by one
  const processFileQueue = async () => {
    if (isProcessingRef.current) return;
    isProcessingRef.current = true;

    const queue = [...fileQueueRef.current];
    fileQueueRef.current = [];

    for (let i = 0; i < queue.length; i++) {
      const file = queue[i];
      const croppedFile = await showCropForFile(file, i + 1, queue.length);

      // Now upload the cropped/original file
      const uploadedImage = await handleUploadImage(croppedFile);
      if (uploadedImage) {
        setUploadedImages((prevImages) => {
          const validPrevImages = Array.isArray(prevImages) ? prevImages : [];
          const newImages = [...validPrevImages, uploadedImage];
          addImages(newImages);
          return newImages;
        });
      }

      // Resolve the dropzone's promise for this file
      const resolver = queueResolversRef.current.get(file.name + file.size + file.lastModified);
      if (resolver) {
        resolver(uploadedImage ? uploadedImage : null);
        queueResolversRef.current.delete(file.name + file.size + file.lastModified);
      }
    }

    isProcessingRef.current = false;
  };

  const dropzone = useDropzone<any, string>({
    onDropFile: async (file: File) => {
      return new Promise((resolve) => {
        // Add file to queue
        fileQueueRef.current.push(file);
        const fileKey = file.name + file.size + file.lastModified;
        queueResolversRef.current.set(fileKey, (result: any) => {
          if (result) {
            resolve({ status: "success", result: result.url });
          } else {
            resolve({ status: "error", error: "Upload failed" });
          }
        });

        // Start processing (will be no-op if already processing)
        // Use setTimeout to batch files that are added in the same tick
        setTimeout(() => processFileQueue(), 50);
      });
    },
    validation: {
      accept: { "image/*": [".png", ".jpg", ".jpeg"] },
      maxSize: 10 * 1024 * 1024, // 10MB limit
      maxFiles: 5
    }
  });

  useEffect(() => {
    setUploadedImages(images)
  }, [images])


  const handleUploadImage = async (file: File) => {
    try {
      const apiRes = await apis.Common.uploadFile("file", file);
      Toast.success("Image uploaded successfully!");

      return {
        id: apiRes?.key || file.name, // ✅ use key for payload
        url: apiRes?.key,             // key used in payload
        name: file.name,
        fullUrl: apiRes?.image_url    // only for preview
      };

    } catch (error) {
      Toast.error("Failed to upload image.");
      return null;
    }
  };

  const handleRemoveImage = (id: string) => {
    const updatedImages = uploadedImages?.filter(img => img.id !== id);
    setUploadedImages(updatedImages);
    addImages(updatedImages);
  };
  return (
    <div className="not-prose flex flex-col gap-4">
      <Dropzone {...dropzone}>
        <div>
          <div className="flex justify-between">
            <DropzoneDescription>
              Select at least 3 images (up to a maximum of 5).
            </DropzoneDescription>
            <DropzoneMessage />
          </div>
          <DropZoneArea>
            {uploadedImages?.length > 0 ? (
              <div className='w-full flex flex-row justify-center items-center p-4 flex-wrap gap-2'>
                {uploadedImages.map((file: any) => (
                  <DropzoneFileListItem
                    className="w-[23%] overflow-hidden rounded-md bg-secondary p-0 shadow-sm"
                    key={file.id}
                    file={file}
                  >
                    <div className="flex relative w-full flex-row h-[150px]">
                      <img
                        src={file.fullUrl ? file.fullUrl : BUCKET_ROOT + file.url}
                        alt={file.name}
                        className="aspect-video object-cover rounded-lg"
                      />
                      <DropzoneRemoveFile
                        className="absolute top-1.5 right-1.5 rounded-full !bg-white text-[var(--primary-brand)] hover:!bg-[var(--primary-brand)] hover:text-white border border-gray-100 shadow-sm transition-all duration-200 h-8 w-8 flex items-center justify-center"
                        onClick={() => handleRemoveImage(file.id)}
                      >
                        <Trash2Icon className="size-4" />
                      </DropzoneRemoveFile>
                    </div>
                  </DropzoneFileListItem>
                ))}
                {uploadedImages.length < 5 && (
                  <DropzoneTrigger className="w-[23%] h-[150px] flex flex-col items-center justify-center bg-transparent content-center text-sm border-dotted border-[#CCCCCC] border-[2px]">
                    <div>
                      <ImagePlus />
                      <p className="font-semibold">Upload photo</p>
                    </div>
                  </DropzoneTrigger>
                )}
              </div>
            ) : (
              <DropzoneTrigger className="flex flex-col items-center gap-4 bg-transparent p-10 text-center text-sm">
                <div>
                  <p className="font-semibold bg-[var(--orange-100)] text-[var(--primary-brand)] p-3 rounded-[100px]">+ Upload photo</p>
                  <p className="text-[12px] text-[#999999]">Supported formats: .png, .jpg</p>
                </div>
              </DropzoneTrigger>
            )}

          </DropZoneArea>
        </div>


      </Dropzone>

      {/* Crop Modal */}
      <Dialog open={cropModalOpen} onOpenChange={(open) => {
        if (!open) handleSkipCrop();
      }}>
        <DialogContent className="sm:max-w-xl max-h-[90vh] flex flex-col p-0 rounded-2xl border-none shadow-2xl overflow-hidden">
          <DialogHeader className="px-6 pt-6 pb-2">
            <DialogTitle className="text-lg font-bold text-[#1C1D22] flex items-center gap-2">
              <Crop className="w-5 h-5 text-[var(--primary-brand)]" />
              <span>Crop Image</span>
              {queueInfo.total > 1 && (
                <span className="ml-auto text-sm font-medium text-gray-400">
                  {queueInfo.current} of {queueInfo.total}
                </span>
              )}
            </DialogTitle>
            {currentFileName && (
              <p className="text-xs text-gray-400 mt-1 truncate">{currentFileName}</p>
            )}
          </DialogHeader>

          <div className="relative w-full h-[350px] bg-gray-900">
            {imageToCrop && (
              <Cropper
                image={imageToCrop}
                crop={crop}
                zoom={zoom}
                aspect={4 / 3}
                onCropChange={setCrop}
                onZoomChange={setZoom}
                onCropComplete={onCropComplete}
              />
            )}
          </div>

          {/* Zoom Controls */}
          <div className="flex items-center justify-center gap-4 px-6 py-3 bg-gray-50">
            <button
              type="button"
              onClick={() => setZoom(z => Math.max(1, z - 0.1))}
              className="w-8 h-8 flex items-center justify-center rounded-full border border-gray-200 hover:bg-gray-100 transition-colors"
            >
              <ZoomOut className="w-4 h-4 text-gray-600" />
            </button>
            <input
              type="range"
              min={1}
              max={3}
              step={0.1}
              value={zoom}
              onChange={(e) => setZoom(Number(e.target.value))}
              className="w-48 h-1.5 accent-[var(--primary-brand)] cursor-pointer"
            />
            <button
              type="button"
              onClick={() => setZoom(z => Math.min(3, z + 0.1))}
              className="w-8 h-8 flex items-center justify-center rounded-full border border-gray-200 hover:bg-gray-100 transition-colors"
            >
              <ZoomIn className="w-4 h-4 text-gray-600" />
            </button>
            <span className="text-xs text-gray-500 font-medium min-w-[40px] text-center">{Math.round(zoom * 100)}%</span>
          </div>

          <DialogFooter className="flex flex-row justify-end gap-3 px-6 pb-6 pt-2">
            <Button
              type="button"
              variant="outline"
              className="h-10 px-6 rounded-xl border-gray-200 font-semibold"
              onClick={handleSkipCrop}
            >
              Skip Crop
            </Button>
            <Button
              type="button"
              variant="theme"
              className="h-10 px-6 rounded-xl font-semibold"
              onClick={handleCropConfirm}
              disabled={isCropping}
            >
              {isCropping ? 'Cropping...' : 'Crop & Upload'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
