import { useState, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { HiUpload, HiX, HiPhotograph, HiDocumentText, HiCheckCircle, HiExclamationCircle } from 'react-icons/hi';
import { HiArrowPath } from 'react-icons/hi2';
import api from '../../services/api';
import './FileUpload.css';

/**
 * Reusable drag-and-drop file upload component.
 *
 * Props:
 *   category    {string}   — storage category: 'profiles' | 'campaigns' | 'gallery' | 'stories' | 'blog' | 'help-requests'
 *   entityId    {string}   — optional related entity ID
 *   accept      {string}   — MIME types for the file input (e.g. "image/*" or "image/*,application/pdf")
 *   label       {string}   — label shown in the drop zone
 *   maxMB       {number}   — client-side file size hint (just for UI; server validates too)
 *   currentUrl  {string}   — existing file URL to show as preview
 *   onUpload    {function} — callback(url, key) called on successful upload
 *   onDelete    {function} — callback(key) called when user removes the file
 *   multiple    {boolean}  — allow multiple file selection
 *   className   {string}   — extra class for the root element
 */
export default function FileUpload({
  category,
  entityId = '',
  accept = 'image/*',
  label = 'Upload a file',
  maxMB = 5,
  currentUrl = '',
  onUpload,
  onDelete,
  multiple = false,
  className = '',
}) {
  const [isDragging, setIsDragging]   = useState(false);
  const [uploading, setUploading]     = useState(false);
  const [progress, setProgress]       = useState(0);
  const [error, setError]             = useState('');
  const [preview, setPreview]         = useState(currentUrl);
  const [uploadedKey, setUploadedKey] = useState('');

  const isImage = (file) => file?.type?.startsWith('image/');

  const handleFiles = useCallback(async (files) => {
    if (!files || files.length === 0) return;
    const file = files[0];  // handle first file (multiple handled separately)

    setError('');
    setProgress(0);

    // Client-side size check
    const maxBytes = maxMB * 1024 * 1024;
    if (file.size > maxBytes) {
      setError(`File too large. Maximum size is ${maxMB}MB.`);
      return;
    }

    // Show local preview for images immediately
    if (isImage(file)) {
      const reader = new FileReader();
      reader.onload = (e) => setPreview(e.target.result);
      reader.readAsDataURL(file);
    }

    setUploading(true);

    try {
      const formData = new FormData();
      formData.append('file', file);
      formData.append('category', category);
      if (entityId) formData.append('entityId', entityId);

      // Use raw axios call for multipart + progress tracking
      // (api interceptor handles auth token)
      const result = await api.post('/upload', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
        onUploadProgress: (e) => {
          const pct = Math.round((e.loaded * 100) / (e.total || 1));
          setProgress(pct);
        },
      });

      const url = result.url || result.previewUrl || '';
      const key = result.key || '';

      setUploadedKey(key);
      if (url) setPreview(url);
      setProgress(100);

      onUpload?.(url, key, result);
    } catch (err) {
      setError(err.message || 'Upload failed. Please try again.');
      // Revert preview on failure
      setPreview(currentUrl);
    } finally {
      setUploading(false);
    }
  }, [category, entityId, maxMB, currentUrl, onUpload]);

  const handleRemove = useCallback(() => {
    const key = uploadedKey;
    setPreview('');
    setUploadedKey('');
    setError('');
    onDelete?.(key);
  }, [uploadedKey, onDelete]);

  // Drag events
  const onDragOver  = (e) => { e.preventDefault(); setIsDragging(true); };
  const onDragLeave = (e) => { e.preventDefault(); setIsDragging(false); };
  const onDrop      = (e) => {
    e.preventDefault();
    setIsDragging(false);
    handleFiles(e.dataTransfer.files);
  };

  const fileIcon = accept.includes('pdf') ? <HiDocumentText /> : <HiPhotograph />;

  return (
    <div className={`fu-root ${className}`}>
      <AnimatePresence mode="wait">
        {preview ? (
          /* ── Preview State ── */
          <motion.div
            key="preview"
            className="fu-preview"
            initial={{ opacity: 0, scale: 0.95 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0, scale: 0.95 }}
          >
            {isImage({ type: accept.startsWith('image') ? 'image/jpeg' : '' }) || preview.match(/\.(jpg|jpeg|png|webp|gif)(\?|$)/i) ? (
              <img src={preview} alt="Upload preview" className="fu-preview__img" />
            ) : (
              <div className="fu-preview__doc">
                <HiDocumentText className="fu-preview__doc-icon" />
                <span>File uploaded</span>
              </div>
            )}
            <button
              type="button"
              className="fu-preview__remove"
              onClick={handleRemove}
              title="Remove file"
            >
              <HiX />
            </button>
            <div className="fu-preview__success">
              <HiCheckCircle /> Uploaded
            </div>
          </motion.div>
        ) : (
          /* ── Drop Zone ── */
          <motion.label
            key="dropzone"
            className={`fu-zone ${isDragging ? 'fu-zone--dragging' : ''} ${uploading ? 'fu-zone--uploading' : ''}`}
            onDragOver={onDragOver}
            onDragLeave={onDragLeave}
            onDrop={onDrop}
            whileHover={{ scale: 1.01 }}
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
          >
            <input
              type="file"
              accept={accept}
              multiple={multiple}
              className="fu-input"
              onChange={(e) => handleFiles(e.target.files)}
              disabled={uploading}
            />

            <div className="fu-zone__icon">
              {uploading ? (
                <HiArrowPath className="spin-icon" />
              ) : isDragging ? (
                <HiUpload />
              ) : (
                fileIcon
              )}
            </div>

            <p className="fu-zone__label">
              {uploading ? 'Uploading…' : isDragging ? 'Drop to upload' : label}
            </p>
            <p className="fu-zone__hint">
              {uploading ? '' : `Drag & drop or click to browse · Max ${maxMB}MB`}
            </p>

            {/* Progress bar */}
            {uploading && (
              <div className="fu-progress">
                <motion.div
                  className="fu-progress__bar"
                  initial={{ width: 0 }}
                  animate={{ width: `${progress}%` }}
                  transition={{ ease: 'easeOut' }}
                />
                <span className="fu-progress__label">{progress}%</span>
              </div>
            )}
          </motion.label>
        )}
      </AnimatePresence>

      {/* Error message */}
      <AnimatePresence>
        {error && (
          <motion.p
            className="fu-error"
            initial={{ opacity: 0, y: -4 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0 }}
          >
            <HiExclamationCircle /> {error}
          </motion.p>
        )}
      </AnimatePresence>
    </div>
  );
}
