import { useCallback, useRef, useState } from "react";
import { Camera, Loader2, X } from "lucide-react";
import { api } from "@/client";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

const MAX_SIZE = 5 * 1024 * 1024; // 5 MB
const ALLOWED_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];

type Props = {
  /** Current avatar URL to display as preview. */
  currentUrl?: string | null;
  /** Called with the returned avatar_url after successful upload. */
  onUploaded: (url: string) => void;
  /** The upload endpoint path (e.g. "/api/v1/user/avatar" or "/api/v1/workspace/my-workspace/avatar"). */
  uploadEndpoint: string;
  /** Accessible label for the component. */
  label?: string;
  /** Size of the avatar preview in Tailwind units (default h-24 w-24). */
  size?: string;
};

export default function AvatarUploader({
  currentUrl,
  onUploaded,
  uploadEndpoint,
  label = "Avatar",
  size = "size-24",
}: Props) {
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [uploading, setUploading] = useState(false);
  const [error, setError] = useState("");
  const [isDragging, setIsDragging] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  const displayUrl = previewUrl ?? currentUrl ?? undefined;

  const upload = useCallback(
    async (file: File) => {
      if (!ALLOWED_TYPES.includes(file.type)) {
        setError("Only PNG, JPEG, WebP, and GIF images are allowed.");
        return;
      }
      if (file.size > MAX_SIZE) {
        setError("Image must be under 5 MB.");
        return;
      }

      setError("");
      setUploading(true);

      try {
        // Show local preview immediately
        const localPreview = URL.createObjectURL(file);
        setPreviewUrl(localPreview);

        // Read file as ArrayBuffer and upload as raw binary
        const buffer = await file.arrayBuffer();
        const res = await api.post<{ avatar_url: string }>(
          uploadEndpoint,
          buffer,
          {
            headers: { "Content-Type": file.type },
          },
        );

        const url = res.data?.avatar_url;
        if (url) {
          onUploaded(url);
        }
      } catch (err) {
        setError(
          err instanceof Error ? err.message : "Failed to upload avatar.",
        );
        setPreviewUrl(null);
      } finally {
        setUploading(false);
      }
    },
    [uploadEndpoint, onUploaded],
  );

  const handleFileChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const file = e.target.files?.[0];
      if (file) upload(file);
      // Reset so the same file can be selected again
      if (inputRef.current) inputRef.current.value = "";
    },
    [upload],
  );

  const handleDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();
      setIsDragging(false);
      const file = e.dataTransfer.files?.[0];
      if (file) upload(file);
    },
    [upload],
  );

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

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

  const handleRemove = useCallback(() => {
    setPreviewUrl(null);
    // Revoke local preview URL to avoid memory leak
    if (previewUrl) URL.revokeObjectURL(previewUrl);
  }, [previewUrl]);

  return (
    <div className="space-y-3">
      <div className="flex items-center gap-4">
        {/* Avatar preview / drop zone */}
        <button
          aria-label={`Upload ${label}`}
          className={cn(
            "relative flex shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-full border-2 transition-all duration-200",
            size,
            isDragging
              ? "border-primary bg-primary/10 scale-105"
              : "border-border/60 bg-muted/30 hover:border-primary/50 hover:bg-accent/40",
          )}
          onClick={() => inputRef.current?.click()}
          onDragLeave={handleDragLeave}
          onDragOver={handleDragOver}
          onDrop={handleDrop}
          type="button"
        >
          {displayUrl ? (
            <img
              alt={label}
              className="size-full rounded-full object-cover"
              src={displayUrl}
            />
          ) : (
            <Camera className="size-6 text-muted-foreground/40" />
          )}

          {uploading && (
            <div className="absolute inset-0 flex items-center justify-center rounded-full bg-background/60 backdrop-blur-[1px]">
              <Loader2 className="size-6 animate-spin text-primary" />
            </div>
          )}
        </button>

        <div className="space-y-1.5">
          <p className="text-sm font-medium text-foreground">{label}</p>
          <p className="text-xs text-muted-foreground/70">
            Click or drag to upload. PNG, JPEG, WebP, GIF up to 5 MB.
          </p>
          {error && (
            <p className="text-xs text-destructive">{error}</p>
          )}
        </div>
      </div>

      {/* Hidden file input */}
      <input
        accept={ALLOWED_TYPES.join(",")}
        className="hidden"
        onChange={handleFileChange}
        ref={inputRef}
        type="file"
      />

      {/* Remove button when preview is local */}
      {previewUrl && !uploading && (
        <Button
          className="h-7 cursor-pointer text-xs"
          onClick={handleRemove}
          size="sm"
          variant="outline"
        >
          <X className="mr-1 size-3" />
          Remove new photo
        </Button>
      )}
    </div>
  );
}
