import { PhotoIcon, XMarkIcon, CheckIcon } from "@heroicons/react/24/outline";
import { motion, AnimatePresence } from "framer-motion";
import { useState, useRef, ChangeEvent } from "react";

type Props = {
  onImageSelected?: (base64: string) => void;
  maxSize?: number;
  title?: string;
  error?: string;
  defaultValue?: string;
  width?: number;
  height?: number;
};

export const ImageUploader = ({
  onImageSelected,
  maxSize,
  title = "تصویر",
  error: externalError,
  defaultValue,
  width,
  height,
}: Props) => {
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [error, setError] = useState<string>("");
  const [showCropModal, setShowCropModal] = useState(false);
  const [imageSrc, setImageSrc] = useState<string>("");
  const [cropFile, setCropFile] = useState<File | null>(null);
  const [cropArea, setCropArea] = useState({ x: 0, y: 0, width: 0, height: 0 });
  const [isDragging, setIsDragging] = useState(false);
  const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
  const fileInputRef = useRef<HTMLInputElement>(null);
  const imageContainerRef = useRef<HTMLDivElement>(null);
  const imageRef = useRef<HTMLImageElement>(null);

  const handleFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    if (!file.type.startsWith("image/")) {
      setError("لطفا یک فایل تصویری انتخاب کنید");
      return;
    }

    if (maxSize && file.size > maxSize) {
      const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(2);
      const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
      setError(
        `حجم فایل (${fileSizeMB} MB) بیشتر از حد مجاز (${maxSizeMB} MB) است`
      );
      setSelectedFile(null);
      if (fileInputRef.current) {
        fileInputRef.current.value = "";
      }
      return;
    }

    // Check image dimensions if width and height are specified
    if (width && height) {
      try {
        const dimensions = await checkImageDimensions(file);
        if (dimensions.width !== width || dimensions.height !== height) {
          // If image is smaller than required, show error
          if (dimensions.width < width || dimensions.height < height) {
            setError(
              `ابعاد تصویر باید حداقل ${width}×${height} پیکسل باشد. ابعاد فعلی: ${dimensions.width}×${dimensions.height} پیکسل`
            );
            setSelectedFile(null);
            if (fileInputRef.current) {
              fileInputRef.current.value = "";
            }
            return;
          }
          // If image is larger, show cropping modal
          if (dimensions.width > width || dimensions.height > height) {
            const base64 = await convertToBase64(file);
            setImageSrc(base64);
            setCropFile(file);
            setShowCropModal(true);
            setError("");
            return;
          }
        }
      } catch {
        setError("خطا در بررسی ابعاد تصویر");
        setSelectedFile(null);
        if (fileInputRef.current) {
          fileInputRef.current.value = "";
        }
        return;
      }
    }

    setError("");

    setSelectedFile(file);

    const base64 = await convertToBase64(file);
    onImageSelected?.(base64);
  };

  const convertToBase64 = (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = (error) => reject(error);
    });
  };

  const checkImageDimensions = (
    file: File
  ): Promise<{ width: number; height: number }> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = (e) => {
        const img = new Image();
        img.onload = () => {
          resolve({ width: img.width, height: img.height });
        };
        img.onerror = () => reject(new Error("Failed to load image"));
        img.src = e.target?.result as string;
      };
      reader.onerror = (error) => reject(error);
    });
  };

  const handleButtonClick = () => {
    fileInputRef.current?.click();
  };

  const handleRemove = (e: React.MouseEvent) => {
    e.stopPropagation();
    setSelectedFile(null);
    setError("");
    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
    onImageSelected?.("");
  };

  const getFileNameFromUrl = (url: string): string => {
    try {
      const urlObj = new URL(url);
      const pathname = urlObj.pathname;
      const fileName = pathname.split("/").pop() || "";
      return fileName;
    } catch {
      const parts = url.split("/");
      return parts[parts.length - 1] || "";
    }
  };

  const initializeCropArea = () => {
    if (!imageRef.current || !width || !height) return;

    const img = imageRef.current;
    const imgRect = img.getBoundingClientRect();

    // Calculate scale factor
    const scaleX = imgRect.width / img.naturalWidth;
    const scaleY = imgRect.height / img.naturalHeight;

    // Calculate crop area size in display pixels
    const cropDisplayWidth = width * scaleX;
    const cropDisplayHeight = height * scaleY;

    // Center the crop area
    const x = (imgRect.width - cropDisplayWidth) / 2;
    const y = (imgRect.height - cropDisplayHeight) / 2;

    setCropArea({
      x: Math.max(0, x),
      y: Math.max(0, y),
      width: Math.min(cropDisplayWidth, imgRect.width),
      height: Math.min(cropDisplayHeight, imgRect.height),
    });
  };

  const handleImageLoad = () => {
    initializeCropArea();
  };

  const handleMouseDown = (e: React.MouseEvent) => {
    if (!imageContainerRef.current || !imageRef.current) return;

    const img = imageRef.current;
    const imgRect = img.getBoundingClientRect();
    const x = e.clientX - imgRect.left;
    const y = e.clientY - imgRect.top;

    // Check if click is within crop area
    if (
      x >= cropArea.x &&
      x <= cropArea.x + cropArea.width &&
      y >= cropArea.y &&
      y <= cropArea.y + cropArea.height
    ) {
      setIsDragging(true);
      setDragStart({
        x: x - cropArea.x,
        y: y - cropArea.y,
      });
    }
  };

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!isDragging || !imageRef.current) return;

    const img = imageRef.current;
    const imgRect = img.getBoundingClientRect();

    const x = e.clientX - imgRect.left - dragStart.x;
    const y = e.clientY - imgRect.top - dragStart.y;

    // Constrain crop area within image bounds
    const maxX = imgRect.width - cropArea.width;
    const maxY = imgRect.height - cropArea.height;

    setCropArea({
      ...cropArea,
      x: Math.max(0, Math.min(x, maxX)),
      y: Math.max(0, Math.min(y, maxY)),
    });
  };

  const handleMouseUp = () => {
    setIsDragging(false);
  };

  const cropImage = async (): Promise<string> => {
    if (!imageRef.current || !cropFile || !width || !height) return "";

    return new Promise((resolve, reject) => {
      const img = imageRef.current!;
      const imgRect = img.getBoundingClientRect();

      // Calculate scale factor
      const scaleX = img.naturalWidth / imgRect.width;
      const scaleY = img.naturalHeight / imgRect.height;

      // Calculate actual crop coordinates in image pixels
      const sourceX = cropArea.x * scaleX;
      const sourceY = cropArea.y * scaleY;
      const sourceWidth = cropArea.width * scaleX;
      const sourceHeight = cropArea.height * scaleY;

      // Create canvas and crop
      const canvas = document.createElement("canvas");
      canvas.width = width;
      canvas.height = height;
      const ctx = canvas.getContext("2d");

      if (!ctx) {
        reject(new Error("Failed to get canvas context"));
        return;
      }

      const image = new Image();
      image.onload = () => {
        ctx.drawImage(
          image,
          sourceX,
          sourceY,
          sourceWidth,
          sourceHeight,
          0,
          0,
          width,
          height
        );
        const base64 = canvas.toDataURL("image/png");
        resolve(base64);
      };
      image.onerror = () => reject(new Error("Failed to load image"));
      image.src = imageSrc;
    });
  };

  const handleCropConfirm = async () => {
    try {
      const croppedBase64 = await cropImage();
      if (croppedBase64 && cropFile) {
        setSelectedFile(cropFile);
        setShowCropModal(false);
        setError("");
        onImageSelected?.(croppedBase64);
      }
    } catch {
      setError("خطا در برش تصویر");
    }
  };

  const handleCropCancel = () => {
    setShowCropModal(false);
    setImageSrc("");
    setCropFile(null);
    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
  };

  const displayError = error || externalError;

  return (
    <div className="flex flex-col gap-2">
      <input
        type="file"
        ref={fileInputRef}
        onChange={handleFileChange}
        className="hidden"
        accept="image/*"
      />
      <button
        type="button"
        onClick={handleButtonClick}
        className={`relative overflow-hidden group ${
          displayError ? "cursor-pointer" : "cursor-pointer"
        }`}
      >
        <motion.span
          className={`flex items-center justify-center gap-1 px-3 py-1.5 text-sm rounded-lg ${
            selectedFile || defaultValue
              ? "bg-success-500/20 text-success-700 dark:text-success-400 dark:bg-success-800/20"
              : "bg-info-500/20 text-info-700 dark:text-primary-400 dark:bg-info-800/20"
          }`}
          initial={false}
          whileTap={{ scale: 0.95 }}
        >
          <motion.span
            className="flex items-center gap-2"
            initial={false}
            animate={
              !selectedFile && !defaultValue
                ? {
                    opacity: [1, 0.7, 1],
                  }
                : {}
            }
            transition={{
              repeat: Infinity,
              duration: 3,
              ease: "easeInOut",
            }}
          >
            {selectedFile
              ? selectedFile.name
              : defaultValue
              ? getFileNameFromUrl(defaultValue)
              : `انتخاب ${title}`}
            <PhotoIcon className="w-4 h-4 ml-1" />
          </motion.span>

          {selectedFile && (
            <button
              type="button"
              onClick={handleRemove}
              className="ml-2 p-0.5 rounded-full hover:bg-red-500/20 dark:hover:bg-red-500/30 transition-colors"
              aria-label="حذف تصویر"
            >
              <XMarkIcon className="w-3.5 h-3.5 text-red-600 dark:text-red-400" />
            </button>
          )}

          <motion.span
            className="absolute inset-0 bg-primary-500/10 opacity-0 group-hover:opacity-100"
            initial={false}
            transition={{ duration: 0.3 }}
            style={{
              borderRadius: "50%",
              scale: 0,
            }}
            whileHover={{
              scale: 2,
              opacity: 0,
              transition: { duration: 0.6 },
            }}
          />
        </motion.span>
      </button>
      {displayError && (
        <p className="text-xs text-red-500 dark:text-red-400">{displayError}</p>
      )}

      <AnimatePresence>
        {showCropModal && width && height && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 dark:bg-black/70"
            onClick={handleCropCancel}
          >
            <motion.div
              initial={{ scale: 0.9, opacity: 0 }}
              animate={{ scale: 1, opacity: 1 }}
              exit={{ scale: 0.9, opacity: 0 }}
              className="bg-white dark:bg-dark-600 rounded-lg p-4 max-w-4xl max-h-[90vh] w-full mx-4 flex flex-col gap-4"
              onClick={(e) => e.stopPropagation()}
            >
              <div className="flex items-center justify-between">
                <h3 className="text-lg font-semibold text-gray-900 dark:text-white">
                  برش تصویر ({width}×{height} پیکسل)
                </h3>
                <button
                  type="button"
                  onClick={handleCropCancel}
                  className="p-1 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700"
                >
                  <XMarkIcon className="w-5 h-5 text-gray-600 dark:text-gray-300" />
                </button>
              </div>

              <div className="flex-1 overflow-auto">
                <div
                  ref={imageContainerRef}
                  className="relative inline-block max-w-full"
                  onMouseDown={handleMouseDown}
                  onMouseMove={handleMouseMove}
                  onMouseUp={handleMouseUp}
                  onMouseLeave={handleMouseUp}
                  style={{ cursor: isDragging ? "grabbing" : "grab" }}
                >
                  <img
                    ref={imageRef}
                    src={imageSrc}
                    alt="Crop"
                    onLoad={handleImageLoad}
                    className="max-w-full h-auto select-none"
                    draggable={false}
                  />
                  {cropArea.width > 0 && cropArea.height > 0 && (
                    <>
                      {/* Overlay */}
                      <div
                        className="absolute inset-0 bg-black/50"
                        style={{
                          clipPath: `polygon(
                            0% 0%,
                            0% 100%,
                            ${cropArea.x}px 100%,
                            ${cropArea.x}px ${cropArea.y}px,
                            ${cropArea.x + cropArea.width}px ${cropArea.y}px,
                            ${cropArea.x + cropArea.width}px ${
                            cropArea.y + cropArea.height
                          }px,
                            ${cropArea.x}px ${cropArea.y + cropArea.height}px,
                            ${cropArea.x}px 100%,
                            100% 100%,
                            100% 0%
                          )`,
                        }}
                      />
                      {/* Crop area border */}
                      <div
                        className="absolute border-2 border-white shadow-lg"
                        style={{
                          left: `${cropArea.x}px`,
                          top: `${cropArea.y}px`,
                          width: `${cropArea.width}px`,
                          height: `${cropArea.height}px`,
                          boxShadow: "0 0 0 2px rgba(59, 130, 246, 0.5)",
                        }}
                      >
                        {/* Corner handles */}
                        <div className="absolute -top-1 -left-1 w-3 h-3 bg-blue-500 border border-white rounded-full" />
                        <div className="absolute -top-1 -right-1 w-3 h-3 bg-blue-500 border border-white rounded-full" />
                        <div className="absolute -bottom-1 -left-1 w-3 h-3 bg-blue-500 border border-white rounded-full" />
                        <div className="absolute -bottom-1 -right-1 w-3 h-3 bg-blue-500 border border-white rounded-full" />
                      </div>
                    </>
                  )}
                </div>
              </div>

              <div className="flex items-center justify-end gap-2">
                <button
                  type="button"
                  onClick={handleCropCancel}
                  className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-200 dark:bg-gray-700 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors"
                >
                  انصراف
                </button>
                <button
                  type="button"
                  onClick={handleCropConfirm}
                  className="px-4 py-2 text-sm font-medium text-white bg-primary-600 dark:bg-primary-500 rounded-lg hover:bg-primary-700 dark:hover:bg-primary-600 transition-colors flex items-center gap-2"
                >
                  <CheckIcon className="w-4 h-4" />
                  تایید
                </button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
};
