"use client";

/**
 * UnifiedMedia
 * 
 * 통합 미디어 컴포넌트
 * - file: 파일 업로드
 * - image: 이미지 업로드/표시
 * - video: 비디오
 * - audio: 오디오
 */

import React, { forwardRef, useCallback, useRef, useState } from "react";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { UnifiedMediaProps } from "@/types/unified-components";
import { Upload, X, File, Image as ImageIcon, Video, Music, Eye, Download, Trash2 } from "lucide-react";

/**
 * 파일 크기 포맷팅
 */
function formatFileSize(bytes: number): string {
  if (bytes === 0) return "0 Bytes";
  const k = 1024;
  const sizes = ["Bytes", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
}

/**
 * 파일 타입 아이콘 가져오기
 */
function getFileIcon(type: string) {
  if (type.startsWith("image/")) return ImageIcon;
  if (type.startsWith("video/")) return Video;
  if (type.startsWith("audio/")) return Music;
  return File;
}

/**
 * 파일 업로드 컴포넌트
 */
const FileUploader = forwardRef<HTMLDivElement, {
  value?: string | string[];
  onChange?: (value: string | string[]) => void;
  multiple?: boolean;
  accept?: string;
  maxSize?: number;
  disabled?: boolean;
  uploadEndpoint?: string;
  className?: string;
}>(({ 
  value, 
  onChange, 
  multiple = false, 
  accept = "*", 
  maxSize = 10485760, // 10MB
  disabled,
  uploadEndpoint = "/api/upload",
  className 
}, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [isUploading, setIsUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const files = Array.isArray(value) ? value : value ? [value] : [];

  // 파일 선택 핸들러
  const handleFileSelect = useCallback(async (selectedFiles: FileList | null) => {
    if (!selectedFiles || selectedFiles.length === 0) return;

    setError(null);
    const fileArray = Array.from(selectedFiles);

    // 크기 검증
    for (const file of fileArray) {
      if (file.size > maxSize) {
        setError(`파일 크기가 ${formatFileSize(maxSize)}를 초과합니다: ${file.name}`);
        return;
      }
    }

    setIsUploading(true);

    try {
      const uploadedUrls: string[] = [];

      for (const file of fileArray) {
        const formData = new FormData();
        formData.append("file", file);

        const response = await fetch(uploadEndpoint, {
          method: "POST",
          body: formData,
        });

        if (!response.ok) {
          throw new Error(`업로드 실패: ${file.name}`);
        }

        const data = await response.json();
        if (data.success && data.url) {
          uploadedUrls.push(data.url);
        } else if (data.filePath) {
          uploadedUrls.push(data.filePath);
        }
      }

      if (multiple) {
        onChange?.([...files, ...uploadedUrls]);
      } else {
        onChange?.(uploadedUrls[0] || "");
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "업로드 중 오류가 발생했습니다");
    } finally {
      setIsUploading(false);
    }
  }, [files, multiple, maxSize, uploadEndpoint, onChange]);

  // 드래그 앤 드롭 핸들러
  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(true);
  }, []);

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

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
    handleFileSelect(e.dataTransfer.files);
  }, [handleFileSelect]);

  // 파일 삭제 핸들러
  const handleRemove = useCallback((index: number) => {
    const newFiles = files.filter((_, i) => i !== index);
    onChange?.(multiple ? newFiles : "");
  }, [files, multiple, onChange]);

  return (
    <div ref={ref} className={cn("space-y-3", className)}>
      {/* 업로드 영역 */}
      <div
        className={cn(
          "border-2 border-dashed rounded-lg p-6 text-center transition-colors",
          isDragging && "border-primary bg-primary/5",
          disabled && "opacity-50 cursor-not-allowed",
          !disabled && "cursor-pointer hover:border-primary/50"
        )}
        onClick={() => !disabled && inputRef.current?.click()}
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
      >
        <input
          ref={inputRef}
          type="file"
          accept={accept}
          multiple={multiple}
          disabled={disabled}
          onChange={(e) => handleFileSelect(e.target.files)}
          className="hidden"
        />
        
        {isUploading ? (
          <div className="flex flex-col items-center gap-2">
            <div className="animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" />
            <span className="text-sm text-muted-foreground">업로드 중...</span>
          </div>
        ) : (
          <div className="flex flex-col items-center gap-2">
            <Upload className="h-8 w-8 text-muted-foreground" />
            <div className="text-sm">
              <span className="font-medium text-primary">클릭</span>
              <span className="text-muted-foreground"> 또는 파일을 드래그하세요</span>
            </div>
            <div className="text-xs text-muted-foreground">
              최대 {formatFileSize(maxSize)}
              {accept !== "*" && ` (${accept})`}
            </div>
          </div>
        )}
      </div>

      {/* 에러 메시지 */}
      {error && (
        <div className="text-sm text-destructive">{error}</div>
      )}

      {/* 업로드된 파일 목록 */}
      {files.length > 0 && (
        <div className="space-y-2">
          {files.map((file, index) => (
            <div
              key={index}
              className="flex items-center gap-2 p-2 bg-muted/50 rounded-md"
            >
              <File className="h-4 w-4 text-muted-foreground" />
              <span className="flex-1 text-sm truncate">{file.split("/").pop()}</span>
              <Button
                variant="ghost"
                size="icon"
                className="h-6 w-6"
                onClick={() => handleRemove(index)}
              >
                <X className="h-3 w-3" />
              </Button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
});
FileUploader.displayName = "FileUploader";

/**
 * 이미지 업로드/표시 컴포넌트
 */
const ImageUploader = forwardRef<HTMLDivElement, {
  value?: string | string[];
  onChange?: (value: string | string[]) => void;
  multiple?: boolean;
  accept?: string;
  maxSize?: number;
  preview?: boolean;
  disabled?: boolean;
  uploadEndpoint?: string;
  className?: string;
}>(({ 
  value, 
  onChange, 
  multiple = false, 
  accept = "image/*", 
  maxSize = 10485760,
  preview = true,
  disabled,
  uploadEndpoint = "/api/upload",
  className 
}, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [isUploading, setIsUploading] = useState(false);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);

  const images = Array.isArray(value) ? value : value ? [value] : [];

  // 파일 선택 핸들러
  const handleFileSelect = useCallback(async (selectedFiles: FileList | null) => {
    if (!selectedFiles || selectedFiles.length === 0) return;

    setIsUploading(true);

    try {
      const fileArray = Array.from(selectedFiles);
      const uploadedUrls: string[] = [];

      for (const file of fileArray) {
        // 미리보기 생성
        if (preview) {
          const reader = new FileReader();
          reader.onload = () => setPreviewUrl(reader.result as string);
          reader.readAsDataURL(file);
        }

        const formData = new FormData();
        formData.append("file", file);

        const response = await fetch(uploadEndpoint, {
          method: "POST",
          body: formData,
        });

        if (response.ok) {
          const data = await response.json();
          if (data.success && data.url) {
            uploadedUrls.push(data.url);
          } else if (data.filePath) {
            uploadedUrls.push(data.filePath);
          }
        }
      }

      if (multiple) {
        onChange?.([...images, ...uploadedUrls]);
      } else {
        onChange?.(uploadedUrls[0] || "");
      }
    } finally {
      setIsUploading(false);
      setPreviewUrl(null);
    }
  }, [images, multiple, preview, uploadEndpoint, onChange]);

  // 이미지 삭제 핸들러
  const handleRemove = useCallback((index: number) => {
    const newImages = images.filter((_, i) => i !== index);
    onChange?.(multiple ? newImages : "");
  }, [images, multiple, onChange]);

  return (
    <div ref={ref} className={cn("space-y-3", className)}>
      {/* 이미지 미리보기 */}
      {preview && images.length > 0 && (
        <div className={cn(
          "grid gap-2",
          multiple ? "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4" : "grid-cols-1"
        )}>
          {images.map((src, index) => (
            <div key={index} className="relative group aspect-square rounded-lg overflow-hidden border">
              <img
                src={src}
                alt={`이미지 ${index + 1}`}
                className="w-full h-full object-cover"
              />
              <div className="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2">
                <Button
                  variant="secondary"
                  size="icon"
                  className="h-8 w-8"
                  onClick={() => window.open(src, "_blank")}
                >
                  <Eye className="h-4 w-4" />
                </Button>
                <Button
                  variant="destructive"
                  size="icon"
                  className="h-8 w-8"
                  onClick={() => handleRemove(index)}
                  disabled={disabled}
                >
                  <Trash2 className="h-4 w-4" />
                </Button>
              </div>
            </div>
          ))}
        </div>
      )}

      {/* 업로드 버튼 */}
      {(!images.length || multiple) && (
        <div
          className={cn(
            "border-2 border-dashed rounded-lg p-4 text-center transition-colors",
            isDragging && "border-primary bg-primary/5",
            disabled && "opacity-50 cursor-not-allowed",
            !disabled && "cursor-pointer hover:border-primary/50"
          )}
          onClick={() => !disabled && inputRef.current?.click()}
          onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
          onDragLeave={(e) => { e.preventDefault(); setIsDragging(false); }}
          onDrop={(e) => { e.preventDefault(); setIsDragging(false); handleFileSelect(e.dataTransfer.files); }}
        >
          <input
            ref={inputRef}
            type="file"
            accept={accept}
            multiple={multiple}
            disabled={disabled}
            onChange={(e) => handleFileSelect(e.target.files)}
            className="hidden"
          />
          
          {isUploading ? (
            <div className="flex items-center justify-center gap-2">
              <div className="animate-spin h-5 w-5 border-2 border-primary border-t-transparent rounded-full" />
              <span className="text-sm text-muted-foreground">업로드 중...</span>
            </div>
          ) : (
            <div className="flex items-center justify-center gap-2">
              <ImageIcon className="h-5 w-5 text-muted-foreground" />
              <span className="text-sm text-muted-foreground">
                이미지 {multiple ? "추가" : "선택"}
              </span>
            </div>
          )}
        </div>
      )}
    </div>
  );
});
ImageUploader.displayName = "ImageUploader";

/**
 * 비디오 컴포넌트
 */
const VideoPlayer = forwardRef<HTMLDivElement, {
  value?: string;
  className?: string;
}>(({ value, className }, ref) => {
  if (!value) {
    return (
      <div
        ref={ref}
        className={cn(
          "aspect-video flex items-center justify-center border rounded-lg bg-muted/50",
          className
        )}
      >
        <Video className="h-8 w-8 text-muted-foreground" />
      </div>
    );
  }

  return (
    <div ref={ref} className={cn("aspect-video rounded-lg overflow-hidden", className)}>
      <video
        src={value}
        controls
        className="w-full h-full object-cover"
      />
    </div>
  );
});
VideoPlayer.displayName = "VideoPlayer";

/**
 * 오디오 컴포넌트
 */
const AudioPlayer = forwardRef<HTMLDivElement, {
  value?: string;
  className?: string;
}>(({ value, className }, ref) => {
  if (!value) {
    return (
      <div
        ref={ref}
        className={cn(
          "h-12 flex items-center justify-center border rounded-lg bg-muted/50",
          className
        )}
      >
        <Music className="h-5 w-5 text-muted-foreground" />
      </div>
    );
  }

  return (
    <div ref={ref} className={cn("", className)}>
      <audio
        src={value}
        controls
        className="w-full"
      />
    </div>
  );
});
AudioPlayer.displayName = "AudioPlayer";

/**
 * 메인 UnifiedMedia 컴포넌트
 */
export const UnifiedMedia = forwardRef<HTMLDivElement, UnifiedMediaProps>(
  (props, ref) => {
    const {
      id,
      label,
      required,
      readonly,
      disabled,
      style,
      size,
      config: configProp,
      value,
      onChange,
    } = props;

    // config가 없으면 기본값 사용
    const config = configProp || { type: "image" as const };

    // 타입별 미디어 컴포넌트 렌더링
    const renderMedia = () => {
      const isDisabled = disabled || readonly;
      const mediaType = config.type || "image";

      switch (mediaType) {
        case "file":
          return (
            <FileUploader
              value={value}
              onChange={onChange}
              multiple={config.multiple}
              accept={config.accept}
              maxSize={config.maxSize}
              disabled={isDisabled}
              uploadEndpoint={config.uploadEndpoint}
            />
          );

        case "image":
          return (
            <ImageUploader
              value={value}
              onChange={onChange}
              multiple={config.multiple}
              accept={config.accept || "image/*"}
              maxSize={config.maxSize}
              preview={config.preview}
              disabled={isDisabled}
              uploadEndpoint={config.uploadEndpoint}
            />
          );

        case "video":
          return (
            <VideoPlayer
              value={typeof value === "string" ? value : value?.[0]}
            />
          );

        case "audio":
          return (
            <AudioPlayer
              value={typeof value === "string" ? value : value?.[0]}
            />
          );

        default:
          return (
            <FileUploader
              value={value}
              onChange={onChange}
              disabled={isDisabled}
            />
          );
      }
    };

    const showLabel = label && style?.labelDisplay !== false;
    const componentWidth = size?.width || style?.width;
    const componentHeight = size?.height || style?.height;

    return (
      <div
        ref={ref}
        id={id}
        className="flex flex-col"
        style={{
          width: componentWidth,
          height: componentHeight,
        }}
      >
        {showLabel && (
          <Label
            htmlFor={id}
            style={{
              fontSize: style?.labelFontSize,
              color: style?.labelColor,
              fontWeight: style?.labelFontWeight,
              marginBottom: style?.labelMarginBottom,
            }}
            className="text-sm font-medium flex-shrink-0"
          >
            {label}
            {required && <span className="text-orange-500 ml-0.5">*</span>}
          </Label>
        )}
        <div className="flex-1 min-h-0">
          {renderMedia()}
        </div>
      </div>
    );
  }
);

UnifiedMedia.displayName = "UnifiedMedia";

export default UnifiedMedia;

