import { useId, useRef, useState } from "react";
import { ImageIcon, Trash2, Upload } from "lucide-react";
import { Button } from "~/components/ui/button";
import { SportIcon } from "~/components/SportIcon";
import { cn } from "~/lib/utils";

interface SportIconOption {
  id: string;
  name: string;
  iconUrl: string;
}

interface SportIconUploaderProps {
  name?: string;
  uploadUrl: string;
  initialIconUrl?: string | null;
  sportName?: string;
  existingIconOptions?: SportIconOption[];
}

const MAX_UPLOAD_BYTES = 1024 * 1024;
const SVG_TYPE = "image/svg+xml";

export function SportIconUploader({
  name = "iconUrl",
  uploadUrl,
  initialIconUrl = null,
  sportName = "Sport icon",
  existingIconOptions = [],
}: SportIconUploaderProps) {
  const selectId = useId();
  const fileInputRef = useRef<HTMLInputElement | null>(null);
  const [iconUrl, setIconUrl] = useState(initialIconUrl ?? "");
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [status, setStatus] = useState<"idle" | "uploading" | "uploaded" | "error">("idle");
  const [error, setError] = useState<string | null>(null);
  const [isDragging, setIsDragging] = useState(false);

  function prepareFile(file: File | undefined) {
    setError(null);
    setStatus("idle");

    if (!file) return;
    if (file.type !== SVG_TYPE && !file.name.toLowerCase().endsWith(".svg")) {
      setError("Choose an SVG file.");
      return;
    }
    if (file.size > MAX_UPLOAD_BYTES) {
      setError("Choose an SVG under 1 MB.");
      return;
    }

    setSelectedFile(file);
    const reader = new FileReader();
    reader.addEventListener("load", () => setPreviewUrl(String(reader.result)));
    reader.readAsDataURL(file);
  }

  function clearSelectedFile() {
    setSelectedFile(null);
    setPreviewUrl(null);
    setError(null);
    setStatus("idle");
  }

  function removeIcon() {
    setIconUrl("");
    clearSelectedFile();
  }

  function chooseExistingIcon(nextIconUrl: string) {
    setIconUrl(nextIconUrl);
    clearSelectedFile();
  }

  async function uploadSelectedFile() {
    if (!selectedFile) {
      setError("Choose an SVG first.");
      return;
    }

    setStatus("uploading");
    setError(null);

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

      const response = await fetch(uploadUrl, { method: "POST", body: formData });
      const result = await response.json().catch(() => ({}));

      if (!response.ok) {
        throw new Error(typeof result.error === "string" ? result.error : "Upload failed.");
      }
      if (typeof result.iconUrl !== "string") {
        throw new Error("Upload response did not include an icon URL.");
      }

      setIconUrl(result.iconUrl);
      setSelectedFile(null);
      setPreviewUrl(null);
      setStatus("uploaded");
    } catch (err) {
      setStatus("error");
      setError(err instanceof Error ? err.message : "Upload failed.");
    }
  }

  return (
    <div className="space-y-4">
      <input type="hidden" name={name} value={iconUrl} />
      <input
        ref={fileInputRef}
        type="file"
        accept=".svg,image/svg+xml"
        onChange={(event) => {
          prepareFile(event.target.files?.[0]);
          event.target.value = "";
        }}
        className="sr-only"
      />

      {existingIconOptions.length > 0 && (
        <div className="space-y-2">
          <label htmlFor={selectId} className="text-sm font-medium">
            Use an existing sport icon
          </label>
          <select
            id={selectId}
            value={existingIconOptions.some((option) => option.iconUrl === iconUrl) ? iconUrl : ""}
            onChange={(event) => chooseExistingIcon(event.target.value)}
            className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
          >
            <option value="">Choose an icon from another sport...</option>
            {existingIconOptions.map((option) => (
              <option key={option.id} value={option.iconUrl}>
                {option.name}
              </option>
            ))}
          </select>
          <p className="text-sm text-muted-foreground">
            Selecting a sport reuses its current icon URL; no upload required.
          </p>
        </div>
      )}

      {iconUrl && !selectedFile && (
        <div className="space-y-3 rounded-md border border-border bg-muted/40 p-4">
          <div className="flex items-center gap-3">
            <SportIcon sportName={sportName} iconUrl={iconUrl} size="lg" />
            <div className="min-w-0">
              <p className="text-sm font-medium">Current icon</p>
              <p className="truncate text-xs text-muted-foreground">{iconUrl}</p>
            </div>
          </div>
          <div className="flex gap-2">
            <Button type="button" variant="outline" onClick={() => fileInputRef.current?.click()}>
              <Upload className="mr-2 h-4 w-4" />
              Replace SVG
            </Button>
            <Button type="button" variant="outline" onClick={removeIcon}>
              <Trash2 className="mr-2 h-4 w-4" />
              Remove
            </Button>
          </div>
        </div>
      )}

      {!iconUrl && !selectedFile && (
        <button
          type="button"
          onClick={() => fileInputRef.current?.click()}
          onDragOver={(event) => {
            event.preventDefault();
            setIsDragging(true);
          }}
          onDragEnter={(event) => {
            event.preventDefault();
            setIsDragging(true);
          }}
          onDragLeave={() => setIsDragging(false)}
          onDrop={(event) => {
            event.preventDefault();
            setIsDragging(false);
            prepareFile(event.dataTransfer.files[0]);
          }}
          className={cn(
            "flex min-h-40 w-full flex-col items-center justify-center rounded-lg border border-dashed bg-card/40 px-6 py-8 text-center transition-colors",
            isDragging ? "border-[#adf661] bg-[#adf661]/10" : "border-border hover:border-muted-foreground hover:bg-accent/40"
          )}
        >
          <ImageIcon className="mb-3 h-9 w-9 text-muted-foreground" />
          <span className="text-sm font-medium text-muted-foreground">Drop an SVG icon</span>
          <span className="text-xs text-muted-foreground/80">or click to browse</span>
        </button>
      )}

      {selectedFile && previewUrl && (
        <div className="space-y-3 rounded-md border border-border bg-background p-4">
          <div className="flex items-center gap-3">
            <img src={previewUrl} alt="" className="h-12 w-12 object-contain" />
            <div className="min-w-0">
              <p className="text-sm font-medium">Ready to upload</p>
              <p className="truncate text-xs text-muted-foreground">{selectedFile.name}</p>
            </div>
          </div>
          <div className="flex gap-2">
            <Button type="button" onClick={uploadSelectedFile} disabled={status === "uploading"}>
              <Upload className="mr-2 h-4 w-4" />
              {status === "uploading" ? "Uploading..." : "Upload SVG"}
            </Button>
            <Button type="button" variant="outline" onClick={clearSelectedFile}>
              <Trash2 className="mr-2 h-4 w-4" />
              Remove
            </Button>
          </div>
        </div>
      )}

      {status === "uploaded" && <p className="text-sm text-[#adf661]">Icon uploaded. Save the sport to apply it.</p>}
      {error && <p className="text-sm text-destructive">{error}</p>}
      <p className="text-sm text-muted-foreground">SVG only, up to 1 MB. Existing local icons keep working until replaced.</p>
    </div>
  );
}
