import { useRef, useState } from "react";
import { AlertTriangle, CheckCircle2, FileText, ImageIcon, Loader2, UploadCloud, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
import { DuplicateUploadError } from "@/lib/api";
import {
  DOCUMENT_ACCEPT,
  formatFileSize,
  MAX_DOCUMENT_SIZE_MB,
  validateDocumentFile,
} from "@/lib/document-upload";
import { cn } from "@/lib/utils";

type UploadPhase = "idle" | "preview" | "uploading" | "done" | "error" | "duplicate";

export function ClientUploadPanel({
  onUpload,
  compact = false,
  className,
}: {
  onUpload: (
    file: File,
    opts?: { onProgress?: (pct: number) => void; forceDuplicate?: boolean },
  ) => Promise<void>;
  compact?: boolean;
  className?: string;
}) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [dragging, setDragging] = useState(false);
  const [phase, setPhase] = useState<UploadPhase>("idle");
  const [progress, setProgress] = useState(0);
  const [file, setFile] = useState<File | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [duplicateExisting, setDuplicateExisting] = useState<DuplicateUploadError["existing"] | null>(
    null,
  );

  const reset = () => {
    if (previewUrl) URL.revokeObjectURL(previewUrl);
    setPreviewUrl(null);
    setPhase("idle");
    setProgress(0);
    setFile(null);
    setError(null);
    setDuplicateExisting(null);
  };

  const pickFile = (list: FileList | null) => {
    const next = list?.[0];
    if (!next) return;
    const validationError = validateDocumentFile(next);
    if (validationError) {
      setPhase("error");
      setError(validationError);
      return;
    }
    if (previewUrl) URL.revokeObjectURL(previewUrl);
    setFile(next);
    setError(null);
    setDuplicateExisting(null);
    if (next.type.startsWith("image/")) {
      setPreviewUrl(URL.createObjectURL(next));
    } else {
      setPreviewUrl(null);
    }
    setPhase("preview");
  };

  const submit = async (forceDuplicate = false) => {
    if (!file) return;
    setPhase("uploading");
    setProgress(0);
    setError(null);
    try {
      await onUpload(file, { onProgress: setProgress, forceDuplicate });
      setPhase("done");
    } catch (err) {
      if (err instanceof DuplicateUploadError) {
        setDuplicateExisting(err.existing);
        setPhase("duplicate");
        return;
      }
      setPhase("error");
      setError(
        err instanceof Error
          ? err.message
          : "We couldn't upload this document. Please try again.",
      );
    }
  };

  if (phase === "duplicate" && file && duplicateExisting) {
    return (
      <div className={cn("space-y-4", className)}>
        <div className="rounded-xl border border-attention/30 bg-attention-soft p-4">
          <div className="flex items-start gap-3">
            <AlertTriangle size={20} className="mt-0.5 text-attention" aria-hidden="true" />
            <div>
              <p className="text-[14px] font-semibold text-foreground">Duplicate document detected</p>
              <p className="mt-1 text-[13px] leading-6 text-muted-foreground">
                An identical document has already been uploaded
                {duplicateExisting.uploadedAt ? ` on ${duplicateExisting.uploadedAt}` : ""}.
              </p>
              <p className="mt-1 text-[12.5px] text-muted-foreground">
                Existing file: {duplicateExisting.file}
              </p>
            </div>
          </div>
        </div>
        <div className="flex flex-wrap justify-end gap-2">
          <Button type="button" variant="outline" onClick={reset}>
            Cancel
          </Button>
          <Button type="button" variant="outline" onClick={() => void submit(true)}>
            Upload anyway
          </Button>
        </div>
      </div>
    );
  }

  if (phase === "done" && file) {
    return (
      <div
        className={cn(
          "rounded-2xl border border-brand/25 bg-brand-soft/50 p-5 text-center md:p-6",
          className,
        )}
        role="status"
        aria-live="polite"
      >
        <span className="mx-auto flex size-12 items-center justify-center rounded-full bg-surface text-brand shadow-sm">
          <CheckCircle2 size={24} aria-hidden="true" />
        </span>
        <p className="mt-3 text-[16px] font-semibold text-foreground">Document sent</p>
        <p className="mt-1 truncate text-[13px] text-muted-foreground">{file.name}</p>
        <p className="mx-auto mt-2 max-w-sm text-[13.5px] leading-relaxed text-muted-foreground">
          We&apos;ve received your document and will process it shortly.
        </p>
        <Button variant="outline" size="sm" className="mt-4" onClick={reset}>
          Upload another
        </Button>
      </div>
    );
  }

  if (phase === "uploading" && file) {
    return (
      <div
        className={cn("rounded-2xl border border-border bg-surface p-5 md:p-6", className)}
        role="status"
        aria-live="polite"
      >
        <div className="flex items-center gap-3">
          <span className="flex size-10 items-center justify-center rounded-xl bg-primary-soft text-primary">
            <Loader2 size={18} className="animate-spin" aria-hidden="true" />
          </span>
          <div className="min-w-0">
            <p className="text-[14px] font-semibold text-foreground">Uploading…</p>
            <p className="truncate text-[13px] text-muted-foreground">{file.name}</p>
          </div>
        </div>
        <Progress value={progress || undefined} className="mt-4 h-2" />
        {progress > 0 ? (
          <p className="mt-2 text-[12px] text-muted-foreground">{progress}% complete</p>
        ) : null}
      </div>
    );
  }

  if (phase === "preview" && file) {
    const isImage = file.type.startsWith("image/");
    return (
      <div className={cn("space-y-4", className)}>
        <div className="rounded-xl border border-border bg-surface p-4">
          <div className="flex items-start gap-3">
            {isImage && previewUrl ? (
              <img
                src={previewUrl}
                alt=""
                className="size-14 shrink-0 rounded-lg object-cover ring-1 ring-border/60"
              />
            ) : (
              <span className="flex size-14 shrink-0 items-center justify-center rounded-lg bg-primary-soft text-primary">
                <FileText size={24} aria-hidden="true" />
              </span>
            )}
            <div className="min-w-0 flex-1">
              <p className="truncate text-[14px] font-semibold text-foreground">{file.name}</p>
              <p className="mt-0.5 text-[12.5px] text-muted-foreground">
                {file.type.includes("pdf") ? "PDF" : "Image"} · {formatFileSize(file.size)}
              </p>
            </div>
            <Button
              type="button"
              variant="ghost"
              size="icon"
              className="shrink-0 text-muted-foreground"
              aria-label="Remove file"
              onClick={reset}
            >
              <X size={16} />
            </Button>
          </div>
        </div>
        <div className="flex flex-wrap justify-end gap-2">
          <Button type="button" variant="outline" onClick={reset}>
            Cancel
          </Button>
          <Button type="button" onClick={() => void submit()}>
            Send document
          </Button>
        </div>
        {error ? (
          <p className="text-[13px] font-medium text-destructive" role="alert">
            {error}
          </p>
        ) : null}
      </div>
    );
  }

  return (
    <div
      onDragOver={(e) => {
        e.preventDefault();
        setDragging(true);
      }}
      onDragLeave={() => setDragging(false)}
      onDrop={(e) => {
        e.preventDefault();
        setDragging(false);
        pickFile(e.dataTransfer.files);
      }}
      className={cn(
        "rounded-2xl border border-dashed transition-colors",
        dragging
          ? "border-brand bg-brand-soft/60"
          : "border-border/90 bg-surface hover:border-brand/40 hover:bg-brand-soft/20",
        compact ? "px-5 py-7" : "px-5 py-9 md:px-8 md:py-10",
        className,
      )}
    >
      <div className="mx-auto flex max-w-md flex-col items-center text-center">
        <span
          className={cn(
            "flex items-center justify-center rounded-2xl bg-brand-soft text-brand-foreground",
            compact ? "size-11" : "size-14",
          )}
        >
          {compact ? (
            <FileText size={22} aria-hidden="true" />
          ) : (
            <UploadCloud size={28} aria-hidden="true" />
          )}
        </span>
        <p
          className={cn(
            "mt-3 font-display font-semibold text-foreground",
            compact ? "text-[17px]" : "text-[19px]",
          )}
        >
          {dragging ? "Drop your document here" : "Drop your invoice here"}
        </p>
        <p className="mt-1 text-[13.5px] text-muted-foreground">or choose a file from your device</p>
        <Button
          variant="brand"
          className="mt-4 gap-2 rounded-full px-5"
          onClick={() => inputRef.current?.click()}
        >
          <UploadCloud size={16} aria-hidden="true" />
          Choose document
        </Button>
        <p className="mt-3 text-[12px] text-muted-foreground">
          PDF, JPG, PNG, WEBP · max {MAX_DOCUMENT_SIZE_MB} MB
        </p>
        {phase === "error" && error ? (
          <p className="mt-3 text-[13px] font-medium text-destructive" role="alert">
            {error}
          </p>
        ) : null}
      </div>
      <input
        ref={inputRef}
        type="file"
        accept={DOCUMENT_ACCEPT}
        className="sr-only"
        aria-label="Choose a file to upload"
        onChange={(e) => {
          pickFile(e.target.files);
          e.target.value = "";
        }}
      />
    </div>
  );
}