"use client";

import { useRef, useState } from "react";
import type { AxiosProgressEvent } from "axios";
import {
  AlertCircle,
  FileCheck,
  Loader2,
  RotateCcw,
  Upload,
} from "lucide-react";
import { toast } from "sonner";

import { reviewApi } from "@/lib/api/client";
import { cn } from "@/lib/utils/cn";
import type { AnnotationUploadResult } from "@/types";

/**
 * Annotated-PDF re-upload for a reviewer. Contract per Phase 2B-iii
 * §3.1 (canonical source) with the {@code matchesOriginal} toast
 * condition corrected per 2026-04-12 reconciliation (warn on match,
 * not inform on mismatch — matches the §2.12 intent of catching the
 * "uploaded the original unchanged" foot-gun).
 *
 * <p>Gated by the parent's {@code visible} prop. Before the reviewer
 * has downloaded the paper, this component renders nothing at all —
 * not a placeholder, not a disabled shell.
 *
 * <p>Native HTML5 drag-and-drop only. No {@code react-dropzone}.
 * Progress is driven by axios's native {@code onUploadProgress}.
 * Replace flow is immediate: click Replace, drop a new file, upload —
 * the backend handles save-new / update-DB / delete-old ordering.
 */
export interface AnnotatedPaperUploadProps {
  reviewId: string;
  paperReferenceNo: string;
  /** When false, the component renders null. Controlled by the parent's hasDownloaded flag. */
  visible: boolean;
}

type UploadState =
  | { kind: "idle" }
  | { kind: "uploading"; progress: number; fileName: string }
  | { kind: "success"; result: AnnotationUploadResult }
  | { kind: "error"; message: string };

function formatSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
}

function formatTimestamp(iso: string): string {
  try {
    return new Date(iso).toLocaleString("en-IN", {
      dateStyle: "medium",
      timeStyle: "short",
    });
  } catch {
    return iso;
  }
}

export function AnnotatedPaperUpload({
  reviewId,
  paperReferenceNo,
  visible,
}: AnnotatedPaperUploadProps) {
  const [state, setState] = useState<UploadState>({ kind: "idle" });
  const [dragActive, setDragActive] = useState(false);
  const dragCounter = useRef(0);
  const inputRef = useRef<HTMLInputElement | null>(null);

  if (!visible) {
    return null;
  }

  function validateAndUpload(file: File) {
    const isPdfMime = file.type === "application/pdf";
    const isPdfExt = file.name.toLowerCase().endsWith(".pdf");
    if (!isPdfMime || !isPdfExt) {
      setState({ kind: "error", message: "Only PDF files are accepted" });
      return;
    }
    uploadFile(file);
  }

  async function uploadFile(file: File) {
    setState({ kind: "uploading", progress: 0, fileName: file.name });
    try {
      const res = await reviewApi.uploadAnnotation(
        reviewId,
        file,
        (event: AxiosProgressEvent) => {
          if (event.total && event.total > 0) {
            const pct = Math.round((event.loaded / event.total) * 100);
            setState({ kind: "uploading", progress: pct, fileName: file.name });
          }
        }
      );
      const result = res.data;
      setState({ kind: "success", result });
      toast.success("Annotated paper uploaded");
      // Warn when the uploaded file is byte-identical to the original
      // manuscript. Catches the reviewer-uploaded-the-wrong-file
      // foot-gun (e.g. they grabbed the downloaded PDF instead of
      // their annotated copy). The match is computed server-side via
      // SHA-256 comparison (Phase 2B-iii §2.12).
      if (result.matchesOriginal) {
        toast.warning(
          "The file you uploaded appears identical to the original manuscript. Did you mean to upload your annotated version?"
        );
      }
    } catch (e) {
      const msg =
        (e as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Upload failed. Please try again.";
      setState({ kind: "error", message: msg });
    }
  }

  function handleDragEnter(e: React.DragEvent<HTMLDivElement>) {
    e.preventDefault();
    e.stopPropagation();
    dragCounter.current += 1;
    if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
      setDragActive(true);
    }
  }

  function handleDragLeave(e: React.DragEvent<HTMLDivElement>) {
    e.preventDefault();
    e.stopPropagation();
    dragCounter.current -= 1;
    if (dragCounter.current <= 0) {
      dragCounter.current = 0;
      setDragActive(false);
    }
  }

  function handleDragOver(e: React.DragEvent<HTMLDivElement>) {
    e.preventDefault();
    e.stopPropagation();
  }

  function handleDrop(e: React.DragEvent<HTMLDivElement>) {
    e.preventDefault();
    e.stopPropagation();
    dragCounter.current = 0;
    setDragActive(false);
    const files = e.dataTransfer.files;
    if (files && files.length > 0) {
      validateAndUpload(files[0]);
    }
  }

  function handleBrowseClick() {
    inputRef.current?.click();
  }

  function handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
    const files = e.target.files;
    if (files && files.length > 0) {
      validateAndUpload(files[0]);
    }
    // Allow re-selecting the same file after a reset.
    e.target.value = "";
  }

  function handleReset() {
    setState({ kind: "idle" });
  }

  return (
    <section className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
      <h3 className="text-base font-semibold text-gray-900">
        Upload annotated PDF
      </h3>
      <p className="mt-1 text-sm text-gray-500">
        Upload your annotated copy of {paperReferenceNo}. Replacing an existing upload
        is immediate — no confirmation.
      </p>

      <input
        ref={inputRef}
        type="file"
        accept="application/pdf"
        className="sr-only"
        onChange={handleInputChange}
      />

      <div className="mt-4">
        {state.kind === "idle" ? (
          <div
            onDragEnter={handleDragEnter}
            onDragLeave={handleDragLeave}
            onDragOver={handleDragOver}
            onDrop={handleDrop}
            onClick={handleBrowseClick}
            role="button"
            tabIndex={0}
            onKeyDown={(e) => {
              if (e.key === "Enter" || e.key === " ") {
                e.preventDefault();
                handleBrowseClick();
              }
            }}
            className={cn(
              "flex cursor-pointer flex-col items-center justify-center rounded-md border-2 border-dashed px-6 py-8 text-center transition",
              dragActive
                ? "border-indigo-500 bg-indigo-50"
                : "border-gray-300 bg-gray-50 hover:border-gray-400 hover:bg-gray-100"
            )}
          >
            <Upload className="h-8 w-8 text-gray-400" aria-hidden="true" />
            <p className="mt-2 text-sm font-medium text-gray-700">
              Drag an annotated PDF here, or click to browse
            </p>
            <p className="mt-1 text-xs text-gray-500">PDF only</p>
          </div>
        ) : null}

        {state.kind === "uploading" ? (
          <div className="rounded-md border border-gray-200 bg-gray-50 p-4">
            <div className="flex items-center gap-2 text-sm text-gray-700">
              <Loader2 className="h-4 w-4 animate-spin" aria-hidden="true" />
              <span className="truncate">Uploading {state.fileName}…</span>
            </div>
            <div className="mt-3 h-2 w-full overflow-hidden rounded-full bg-gray-200">
              <div
                className="h-full bg-indigo-600 transition-all"
                style={{ width: `${state.progress}%` }}
              />
            </div>
            <p className="mt-1 text-right text-xs text-gray-500">{state.progress}%</p>
          </div>
        ) : null}

        {state.kind === "success" ? (
          <div className="rounded-md border border-green-200 bg-green-50 p-4">
            <div className="flex items-start gap-3">
              <FileCheck
                className="mt-0.5 h-5 w-5 shrink-0 text-green-600"
                aria-hidden="true"
              />
              <div className="flex-1 min-w-0">
                <p className="truncate text-sm font-medium text-gray-900">
                  {state.result.filename}
                </p>
                <p className="mt-0.5 text-xs text-gray-600">
                  {formatSize(state.result.sizeBytes)} · uploaded{" "}
                  {formatTimestamp(state.result.uploadedAt)}
                </p>
              </div>
              <button
                type="button"
                onClick={handleReset}
                className="inline-flex items-center gap-1 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-xs font-medium text-gray-700 shadow-sm hover:bg-gray-50"
              >
                <RotateCcw className="h-3.5 w-3.5" aria-hidden="true" />
                Replace
              </button>
            </div>
          </div>
        ) : null}

        {state.kind === "error" ? (
          <div className="rounded-md border border-red-200 bg-red-50 p-4">
            <div className="flex items-start gap-3">
              <AlertCircle
                className="mt-0.5 h-5 w-5 shrink-0 text-red-600"
                aria-hidden="true"
              />
              <div className="flex-1">
                <p className="text-sm font-medium text-red-900">Upload failed</p>
                <p className="mt-0.5 text-xs text-red-800">{state.message}</p>
              </div>
              <button
                type="button"
                onClick={handleReset}
                className="inline-flex items-center gap-1 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-xs font-medium text-gray-700 shadow-sm hover:bg-gray-50"
              >
                Try again
              </button>
            </div>
          </div>
        ) : null}
      </div>
    </section>
  );
}

export default AnnotatedPaperUpload;
