"use client";

import { useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  uploadedFileSchema,
  UPLOAD_RULES,
  type UploadKind,
  type UploadedFileMetadata,
} from "@/lib/validations/upload";

type FileUploadProps = {
  kind: UploadKind;
  onUploaded: (files: UploadedFileMetadata[]) => void;
  id?: string;
  multiple?: boolean;
  label?: string;
  helperText?: string;
};

const defaultLabels: Record<UploadKind, string> = {
  image: "Image",
  audio: "Audio",
};

export default function FileUpload({
  kind,
  onUploaded,
  id,
  multiple = false,
  label,
  helperText,
}: FileUploadProps) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [isUploading, setIsUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const rules = UPLOAD_RULES[kind];
  const fieldId = id ?? `file-upload-${kind}`;

  async function handleFiles(selectedFiles: File[]) {
    setError(null);
    setIsUploading(true);

    try {
      const uploaded: UploadedFileMetadata[] = [];

      for (const file of selectedFiles) {
        if (!rules.mimeTypes.includes(file.type) || file.size > rules.maxBytes) {
          throw new Error(`Unsupported or oversized ${kind} file.`);
        }

        const body = new FormData();
        body.set("kind", kind);
        body.set("file", file);

        const response = await fetch("/api/upload", { method: "POST", body });
        const payload: unknown = await response.json();

        if (!response.ok) {
          const message =
            typeof payload === "object" && payload !== null && "error" in payload
              ? String(payload.error)
              : "The file could not be uploaded.";
          throw new Error(message);
        }

        const parsed = uploadedFileSchema.safeParse(payload);
        if (!parsed.success) {
          throw new Error("The upload response was invalid.");
        }

        uploaded.push(parsed.data);
      }

      onUploaded(uploaded);
    } catch (uploadError) {
      setError(uploadError instanceof Error ? uploadError.message : "The file could not be uploaded.");
    } finally {
      setIsUploading(false);
      if (inputRef.current) {
        inputRef.current.value = "";
      }
    }
  }

  return (
    <div className="space-y-2" dir="auto">
      <Label htmlFor={fieldId}>{label ?? defaultLabels[kind]}</Label>
      <div className="flex flex-col gap-2 sm:flex-row sm:items-center">
        <Input
          ref={inputRef}
          id={fieldId}
          type="file"
          accept={rules.accept}
          multiple={multiple}
          disabled={isUploading}
          onChange={(event) => {
            void handleFiles(Array.from(event.target.files ?? []));
          }}
        />
        {isUploading ? (
          <Button type="button" variant="secondary" disabled>
            Uploading…
          </Button>
        ) : null}
      </div>
      <p className="text-xs text-muted-foreground">
        {helperText ?? `Maximum ${Math.round(rules.maxBytes / (1024 * 1024))} MB.`}
      </p>
      {error ? <p className="text-sm text-destructive">{error}</p> : null}
    </div>
  );
}
