"use client";

import { useEffect, useRef, useState } from "react";
import type { ChangeEvent, ClipboardEvent, DragEvent, KeyboardEvent } from "react";
import { AlertCircle, FileText, ImageIcon, RefreshCw, Trash2, UploadCloud, X } from "lucide-react";
import { RECEIPT_ACCEPT, receiptKind, validateReceiptFile } from "@/lib/receipts";
import { ReceiptViewer } from "@/components/ReceiptViewer";

type ReceiptUploaderProps = {
  name?: string;
  deleteName?: string;
  label?: string;
  multiple?: boolean;
  existingUrl?: string | null;
  existingFileName?: string | null;
  existingMimeType?: string | null;
  allowDelete?: boolean;
};

function screenshotFileName(date = new Date()) {
  const yyyy = String(date.getFullYear());
  const mm = String(date.getMonth() + 1).padStart(2, "0");
  const dd = String(date.getDate()).padStart(2, "0");
  const hh = String(date.getHours()).padStart(2, "0");
  const mi = String(date.getMinutes()).padStart(2, "0");
  const ss = String(date.getSeconds()).padStart(2, "0");
  return `receipt-screenshot-${yyyy}${mm}${dd}-${hh}${mi}${ss}.png`;
}

function buildFileList(files: File[]) {
  const dataTransfer = new DataTransfer();
  files.forEach((file) => dataTransfer.items.add(file));
  return dataTransfer.files;
}

export function ReceiptUploader({
  name = "receipt",
  deleteName = "deleteReceipt",
  label = "Receipt image/PDF",
  multiple = false,
  existingUrl,
  existingFileName,
  existingMimeType,
  allowDelete = false
}: ReceiptUploaderProps) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
  const [previewUrls, setPreviewUrls] = useState<string[]>([]);
  const [deleteRequested, setDeleteRequested] = useState(false);
  const [deletePrompt, setDeletePrompt] = useState<{ clearNewReceipt: boolean } | null>(null);
  const [dragActive, setDragActive] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    return () => {
      previewUrls.forEach((url) => URL.revokeObjectURL(url));
    };
  }, [previewUrls]);

  const existingKind = existingUrl ? receiptKind(existingFileName ?? existingUrl, existingMimeType) : null;
  const hasExistingReceipt = Boolean(existingUrl) && !deleteRequested;

  const setReceiptFiles = (nextFiles: File[]) => {
    const acceptedFiles = multiple ? nextFiles : nextFiles.slice(0, 1);
    for (const file of acceptedFiles) {
      const validation = validateReceiptFile(file);
      if (!validation.valid) {
        setError(validation.message);
        if (inputRef.current) inputRef.current.value = "";
        return;
      }
    }

    setError(null);
    setSelectedFiles(acceptedFiles);
    if (inputRef.current) {
      inputRef.current.files = buildFileList(acceptedFiles);
    }

    setPreviewUrls((currentUrls) => {
      currentUrls.forEach((url) => URL.revokeObjectURL(url));
      return acceptedFiles.map((file) => URL.createObjectURL(file));
    });
  };

  const clearSelectedFile = (index?: number) => {
    const nextFiles = typeof index === "number" ? selectedFiles.filter((_, fileIndex) => fileIndex !== index) : [];
    setReceiptFiles(nextFiles);
    if (nextFiles.length === 0 && inputRef.current) inputRef.current.value = "";
  };

  const onInputChange = (event: ChangeEvent<HTMLInputElement>) => {
    setReceiptFiles(Array.from(event.currentTarget.files ?? []));
  };

  const onDrop = (event: DragEvent<HTMLDivElement>) => {
    event.preventDefault();
    setDragActive(false);
    const files = Array.from(event.dataTransfer.files ?? []);
    if (files.length > 0) {
      setReceiptFiles(files);
    } else {
      setError("Drop a JPG, PNG, WEBP, or PDF receipt file here.");
    }
  };

  const onPaste = (event: ClipboardEvent<HTMLDivElement>) => {
    const items: DataTransferItem[] = [];
    for (let index = 0; index < event.clipboardData.items.length; index += 1) {
      const item = event.clipboardData.items[index];
      if (item) items.push(item);
    }
    const imageItem = items.find((item) => item.kind === "file" && item.type.startsWith("image/"));

    if (!imageItem) {
      setError("Paste an image screenshot here, or upload a receipt file.");
      return;
    }

    const pastedFile = imageItem.getAsFile();
    if (!pastedFile) {
      setError("Could not read that screenshot. Please paste it again.");
      return;
    }

    event.preventDefault();
    const file = new File([pastedFile], screenshotFileName(), { type: pastedFile.type || "image/png" });
    setReceiptFiles([file]);
  };

  const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
    if (event.key === "Enter" || event.key === " ") {
      event.preventDefault();
      inputRef.current?.click();
    }
  };

  const requestDeleteExisting = (clearNewReceipt = true) => {
    setDeletePrompt({ clearNewReceipt });
  };

  const confirmDeleteExisting = () => {
    setDeleteRequested(true);
    if (deletePrompt?.clearNewReceipt) clearSelectedFile();
    setError(null);
    setDeletePrompt(null);
  };

  const cancelDeleteExisting = () => {
    setDeleteRequested(false);
    setError(null);
  };

  return (
    <div className="grid gap-2">
      <span className="label">{label}</span>
      <input ref={inputRef} className="sr-only" name={name} type="file" accept={RECEIPT_ACCEPT} multiple={multiple} onChange={onInputChange} />
      {deleteRequested ? <input type="hidden" name={deleteName} value="on" /> : null}

      <div
        className={`grid cursor-pointer gap-3 rounded-md border border-dashed p-4 text-sm transition ${
          dragActive ? "border-blue-500 bg-blue-50" : "border-line bg-white hover:border-blue-300 hover:bg-slate-50"
        }`}
        role="button"
        tabIndex={0}
        onClick={(event) => {
          const target = event.target as HTMLElement;
          if (target.closest("button,a,input")) return;
          inputRef.current?.click();
        }}
        onDragOver={(event) => {
          event.preventDefault();
          setDragActive(true);
        }}
        onDragLeave={() => setDragActive(false)}
        onDrop={onDrop}
        onPaste={onPaste}
        onKeyDown={onKeyDown}
      >
        <div className="flex items-start gap-3">
          <div className="grid h-10 w-10 shrink-0 place-items-center rounded-md bg-blue-50 text-blue-700">
            <UploadCloud className="h-5 w-5" aria-hidden="true" />
          </div>
          <div className="grid gap-1">
            <p className="font-medium text-ink">Upload receipt, drag file here, or paste screenshot with Ctrl+V / Cmd+V</p>
            <p className="text-xs text-slate-500">JPG, JPEG, PNG, WEBP, or PDF up to 10 MB.</p>
          </div>
        </div>

        {selectedFiles.length > 0 ? (
          <div className="grid gap-3 rounded-md border border-line bg-slate-50 p-3">
            {existingUrl && allowDelete && !deleteRequested ? (
              <button className="btn-danger justify-self-start px-2 py-1 text-xs" type="button" onClick={() => requestDeleteExisting(false)}>
                <Trash2 className="h-4 w-4" aria-hidden="true" />
                Delete old receipt files
              </button>
            ) : null}
            {selectedFiles.map((selectedFile, index) => {
              const selectedKind = receiptKind(selectedFile.name, selectedFile.type);
              const previewUrl = previewUrls[index];
              return (
                <div key={`${selectedFile.name}-${index}`} className="grid gap-3 rounded-md border border-line bg-white p-3">
                  <div className="flex items-center justify-between gap-3">
                    <div className="flex min-w-0 items-center gap-2">
                      {selectedKind === "pdf" ? <FileText className="h-5 w-5 shrink-0 text-red-600" aria-hidden="true" /> : <ImageIcon className="h-5 w-5 shrink-0 text-emerald-700" aria-hidden="true" />}
                      <span className="truncate text-sm font-medium text-ink">{selectedFile.name}</span>
                    </div>
                    <button className="btn-secondary px-2 py-1 text-xs" type="button" onClick={() => clearSelectedFile(index)}>
                      <X className="h-4 w-4" aria-hidden="true" />
                      Remove
                    </button>
                  </div>
                  {selectedKind === "pdf" && previewUrl ? (
                    <ReceiptViewer url={previewUrl} fileName={selectedFile.name} mimeType={selectedFile.type} buttonLabel="View PDF" checkBeforeOpen={false} />
                  ) : previewUrl ? (
                    // eslint-disable-next-line @next/next/no-img-element
                    <img className="max-h-44 w-full rounded-md border border-line bg-white object-contain p-2" src={previewUrl} alt="Selected receipt preview" />
                  ) : null}
                </div>
              );
            })}
          </div>
        ) : null}

        {selectedFiles.length === 0 && hasExistingReceipt ? (
          <div className="grid gap-3 rounded-md border border-line bg-slate-50 p-3">
            <div className="flex items-center justify-between gap-3">
              <div className="flex min-w-0 items-center gap-2">
                {existingKind === "pdf" ? <FileText className="h-5 w-5 shrink-0 text-red-600" aria-hidden="true" /> : <ImageIcon className="h-5 w-5 shrink-0 text-emerald-700" aria-hidden="true" />}
                <span className="truncate text-sm font-medium text-ink">{existingFileName ?? "Existing receipt"}</span>
              </div>
              <div className="flex flex-wrap gap-2">
                <button className="btn-secondary px-2 py-1 text-xs" type="button" onClick={() => inputRef.current?.click()}>
                  <RefreshCw className="h-4 w-4" aria-hidden="true" />
                  Replace
                </button>
                {allowDelete ? (
                  <button className="btn-danger px-2 py-1 text-xs" type="button" onClick={() => requestDeleteExisting()}>
                    <Trash2 className="h-4 w-4" aria-hidden="true" />
                    Delete
                  </button>
                ) : null}
              </div>
            </div>
            {existingKind === "image" ? (
              // eslint-disable-next-line @next/next/no-img-element
              <img className="max-h-44 w-full rounded-md border border-line bg-white object-contain p-2" src={existingUrl ?? ""} alt="Existing receipt preview" />
            ) : (
              <ReceiptViewer url={existingUrl} fileName={existingFileName} mimeType={existingMimeType} buttonLabel="View PDF" />
            )}
          </div>
        ) : null}

        {selectedFiles.length === 0 && !hasExistingReceipt && !deleteRequested ? (
          <p className="rounded-md border border-line bg-slate-50 px-3 py-2 text-sm text-slate-500">No receipt uploaded</p>
        ) : null}

        {deleteRequested ? (
          <div className="flex flex-wrap items-center justify-between gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm font-medium text-amber-800">
            <span>{selectedFiles.length > 0 ? "Old receipt files will be deleted when you save." : "Receipt will be deleted when you save."}</span>
            <button className="btn-secondary px-2 py-1 text-xs" type="button" onClick={cancelDeleteExisting}>
              Keep receipt
            </button>
          </div>
        ) : null}

        <button className="btn-secondary justify-self-start" type="button" onClick={() => inputRef.current?.click()}>
          <UploadCloud className="h-4 w-4" aria-hidden="true" />
          Choose file
        </button>
      </div>

      {error ? (
        <p className="flex items-center gap-1 text-xs font-medium text-red-600">
          <AlertCircle className="h-3.5 w-3.5" aria-hidden="true" />
          {error}
        </p>
      ) : null}

      {deletePrompt ? (
        <div className="fixed inset-0 z-50 grid place-items-center bg-slate-950/60 p-4" role="dialog" aria-modal="true">
          <div className="w-full max-w-md rounded-md bg-white p-5 shadow-2xl">
            <h3 className="font-semibold text-ink">Confirm receipt delete</h3>
            <p className="mt-2 text-sm text-slate-600">Delete this receipt when you save the record? You can cancel and keep the existing receipt.</p>
            <div className="mt-5 flex flex-wrap justify-end gap-2">
              <button className="btn-secondary" type="button" onClick={() => setDeletePrompt(null)}>Cancel</button>
              <button className="btn-danger" type="button" onClick={confirmDeleteExisting}>Confirm Delete</button>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  );
}
