'use client';

/**
 * ImageUploader Component
 * 图片上传组件 - 支持拖拽、粘贴和点击上传
 */

import React, { useCallback, useRef, useState, useMemo } from 'react';
import { cn } from '@/lib/utils';
import { ImageIcon, Upload, X, Loader2 } from 'lucide-react';
import { useTranslation } from '@/hooks/useTranslation';

export interface ImageUploaderProps {
  /** 上传处理函数 */
  onUpload: (file: File) => Promise<string>;
  /** 上传成功回调 */
  onSuccess?: (url: string) => void;
  /** 上传失败回调 */
  onError?: (error: Error) => void;
  /** 关闭回调 */
  onClose?: () => void;
  /** 允许的图片类型 */
  allowedTypes?: string[];
  /** 最大文件大小（字节） */
  maxSize?: number;
  /** 自定义类名 */
  className?: string;
}

const DEFAULT_ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'];
const DEFAULT_MAX_SIZE = 10 * 1024 * 1024; // 10MB

export function ImageUploader({
  onUpload,
  onSuccess,
  onError,
  onClose,
  allowedTypes = DEFAULT_ALLOWED_TYPES,
  maxSize = DEFAULT_MAX_SIZE,
  className,
}: ImageUploaderProps) {
  const { t } = useTranslation();
  const [isDragging, setIsDragging] = useState(false);
  const [isUploading, setIsUploading] = useState(false);
  const [preview, setPreview] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const supportedTypesText = useMemo(() => {
    const typeMap: Record<string, string> = {
      'image/jpeg': 'JPG',
      'image/png': 'PNG',
      'image/gif': 'GIF',
      'image/webp': 'WebP',
      'image/svg+xml': 'SVG',
    };
    const labelList = allowedTypes.map((type) => typeMap[type] || type);
    return labelList.join(t.documentEditor.imageUploader.typesSeparator);
  }, [allowedTypes, t]);

  const validateFile = useCallback(
    (file: File): string | null => {
      if (!allowedTypes.includes(file.type)) {
        return t.documentEditor.imageUploader.errors.unsupportedType.replace(
          '{type}',
          file.type
        );
      }
      if (file.size > maxSize) {
        const maxSizeMB = (maxSize / 1024 / 1024).toFixed(1);
        return t.documentEditor.imageUploader.errors.maxSizeExceeded.replace(
          '{max}',
          maxSizeMB
        );
      }
      return null;
    },
    [allowedTypes, maxSize, t]
  );

  const handleFile = useCallback(
    async (file: File) => {
      setError(null);

      const validationError = validateFile(file);
      if (validationError) {
        setError(validationError);
        onError?.(new Error(validationError));
        return;
      }

      // 显示预览
      const previewUrl = URL.createObjectURL(file);
      setPreview(previewUrl);

      // 开始上传
      setIsUploading(true);
      try {
        const url = await onUpload(file);
        onSuccess?.(url);
        onClose?.();
      } catch (err) {
        const error =
          err instanceof Error
            ? err
            : new Error(t.documentEditor.imageUploader.errors.uploadFailed);
        setError(error.message);
        onError?.(error);
      } finally {
        setIsUploading(false);
        URL.revokeObjectURL(previewUrl);
      }
    },
    [validateFile, onUpload, onSuccess, onError, onClose]
  );

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(true);
  }, []);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(false);
  }, []);

  const handleDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();
      e.stopPropagation();
      setIsDragging(false);

      const files = e.dataTransfer.files;
      if (files.length > 0) {
        const file = files[0];
        if (file.type.startsWith('image/')) {
          handleFile(file);
        }
      }
    },
    [handleFile]
  );

  const handleClick = useCallback(() => {
    fileInputRef.current?.click();
  }, []);

  const handleFileChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const files = e.target.files;
      if (files && files.length > 0) {
        handleFile(files[0]);
      }
      // 重置 input 以允许重复选择相同文件
      e.target.value = '';
    },
    [handleFile]
  );

  const handlePaste = useCallback(
    (e: React.ClipboardEvent) => {
      const items = e.clipboardData.items;
      for (let i = 0; i < items.length; i++) {
        const item = items[i];
        if (item.type.startsWith('image/')) {
          const file = item.getAsFile();
          if (file) {
            handleFile(file);
            break;
          }
        }
      }
    },
    [handleFile]
  );

  const clearPreview = useCallback(() => {
    if (preview) {
      URL.revokeObjectURL(preview);
    }
    setPreview(null);
    setError(null);
  }, [preview]);

  return (
    <div
      className={cn(
        'image-uploader relative rounded-lg border-2 border-dashed p-6 transition-colors',
        isDragging ? 'border-blue-500 bg-blue-50' : 'border-gray-300 bg-gray-50',
        isUploading && 'pointer-events-none opacity-70',
        className
      )}
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
      onPaste={handlePaste}
    >
      <input
        ref={fileInputRef}
        type="file"
        accept={allowedTypes.join(',')}
        onChange={handleFileChange}
        className="hidden"
      />

      {preview ? (
        <div className="relative">
          <img
            src={preview}
            alt={t.documentEditor.imageUploader.previewAlt}
            className="mx-auto max-h-48 rounded-lg object-contain"
          />
          {!isUploading && (
            <button
              type="button"
              onClick={clearPreview}
              className="absolute -right-2 -top-2 rounded-full bg-gray-800 p-1 text-white hover:bg-gray-700"
            >
              <X className="h-4 w-4" />
            </button>
          )}
          {isUploading && (
            <div className="absolute inset-0 flex items-center justify-center rounded-lg bg-white/70">
              <Loader2 className="h-8 w-8 animate-spin text-blue-500" />
            </div>
          )}
        </div>
      ) : (
        <div
          className="flex cursor-pointer flex-col items-center gap-3 text-center"
          onClick={handleClick}
        >
          <div className="rounded-full bg-gray-200 p-3">
            <ImageIcon className="h-6 w-6 text-gray-500" />
          </div>
          <div>
            <p className="text-sm font-medium text-gray-700">
              {t.documentEditor.imageUploader.dropHint}
            </p>
            <p className="mt-1 text-xs text-gray-500">
              {t.documentEditor.imageUploader.supportHint
                .replace('{types}', supportedTypesText)
                .replace('{max}', (maxSize / 1024 / 1024).toFixed(0))}
            </p>
          </div>
          <button
            type="button"
            className="mt-2 inline-flex items-center gap-2 rounded-md bg-blue-500 px-4 py-2 text-sm font-medium text-white hover:bg-blue-600"
          >
            <Upload className="h-4 w-4" />
            {t.documentEditor.imageUploader.selectImage}
          </button>
        </div>
      )}

      {error && (
        <div className="mt-3 rounded-md bg-red-50 p-2 text-center text-sm text-red-600">
          {error}
        </div>
      )}
    </div>
  );
}

export default ImageUploader;
