import { useEffect, useRef, useState } from 'react';
import { ExternalLink, Loader2, PenLine, RotateCcw } from 'lucide-react';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '../components/ui/dialog';
import { Button } from '../components/ui/button';
import { downloadPdfBlob } from './applicationFormOfficialPdf';
import { PdfTextLayoutEditorDialog } from './PdfTextLayoutEditorDialog';
import {
  EMPTY_OFFICIAL_FORM_PREVIEW_FIELDS,
  hasOfficialFormPreviewFieldChanges,
  OFFICIAL_FORM_PREVIEW_FIELD_DEFS,
  sanitizeOfficialFormPreviewFields,
  toOfficialFormPreviewOverlayEdits,
  type OfficialFormPreviewFieldKey,
  type OfficialFormPreviewFields,
} from './officialFormPreviewFieldEdits';
import { applyPdfTextLayoutEdits, type PdfTextLayoutEdit } from './pdfLayoutEditor';
import { cn } from '../lib/utils';
import { toast } from 'sonner';
import { detailFromApiError } from '../api/client';
import { getOfficialFormLayout, saveOfficialFormLayout } from '../lib/officialFormLayoutApi';

export type OfficialFormPdfPreviewDialogProps = {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** When null and not loading, dialog shows empty body. */
  pdfBlob: Blob | null;
  fileName: string;
  /** Show progress in the dialog body (during generation). */
  loading?: boolean;
  /** Explains LibreOffice (server / MinIO) vs client fallback, set by {@link createOfficialFormPdfFromDrafts}. */
  sourceNote?: string | null;
  caseId?: string;
  /** Initial values for client-only field edits. */
  initialPreviewFields?: OfficialFormPreviewFields;
  className?: string;
};

/**
 * Inline PDF review via blob URL. Some browsers block embedded PDFs; a “new tab” fallback is provided.
 */
export function OfficialFormPdfPreviewDialog({
  open,
  onOpenChange,
  pdfBlob,
  fileName,
  loading = false,
  sourceNote,
  caseId,
  initialPreviewFields,
  className,
}: OfficialFormPdfPreviewDialogProps) {
  const [basePdfBlob, setBasePdfBlob] = useState<Blob | null>(null);
  const [workingPdfBlob, setWorkingPdfBlob] = useState<Blob | null>(null);
  const [objectUrl, setObjectUrl] = useState<string | null>(null);
  const [fieldValues, setFieldValues] = useState<OfficialFormPreviewFields>(EMPTY_OFFICIAL_FORM_PREVIEW_FIELDS);
  const [applyingFieldPreview, setApplyingFieldPreview] = useState(false);
  const [layoutEditorOpen, setLayoutEditorOpen] = useState(false);
  const [initialLayoutEdits, setInitialLayoutEdits] = useState<PdfTextLayoutEdit[]>([]);
  const applyVersionRef = useRef(0);

  useEffect(() => {
    if (!open || !workingPdfBlob) {
      setObjectUrl(null);
      return;
    }
    const url = URL.createObjectURL(workingPdfBlob);
    setObjectUrl(url);
    return () => {
      URL.revokeObjectURL(url);
    };
  }, [open, workingPdfBlob]);

  useEffect(() => {
    setBasePdfBlob(pdfBlob);
    setWorkingPdfBlob(pdfBlob);
  }, [pdfBlob]);

  useEffect(() => {
    setFieldValues(sanitizeOfficialFormPreviewFields(initialPreviewFields ?? EMPTY_OFFICIAL_FORM_PREVIEW_FIELDS));
  }, [initialPreviewFields, open]);

  useEffect(() => {
    if (!open || !basePdfBlob || loading) return;
    const baseValues = sanitizeOfficialFormPreviewFields(initialPreviewFields ?? EMPTY_OFFICIAL_FORM_PREVIEW_FIELDS);
    const nextValues = sanitizeOfficialFormPreviewFields(fieldValues);
    const changed = hasOfficialFormPreviewFieldChanges(nextValues, baseValues);
    const edits = changed ? toOfficialFormPreviewOverlayEdits(nextValues) : [];
    const myVersion = ++applyVersionRef.current;
    const timer = window.setTimeout(() => {
      if (edits.length === 0) {
        setWorkingPdfBlob(basePdfBlob);
        setApplyingFieldPreview(false);
        return;
      }
      setApplyingFieldPreview(true);
      void (async () => {
        try {
          const nextBlob = await applyPdfTextLayoutEdits(basePdfBlob, edits);
          if (applyVersionRef.current !== myVersion) return;
          setWorkingPdfBlob(nextBlob);
        } finally {
          if (applyVersionRef.current === myVersion) {
            setApplyingFieldPreview(false);
          }
        }
      })();
    }, 250);
    return () => {
      window.clearTimeout(timer);
    };
  }, [basePdfBlob, fieldValues, initialPreviewFields, loading, open]);

  const openInNewTab = () => {
    if (!objectUrl) return;
    window.open(objectUrl, '_blank', 'noopener,noreferrer');
  };

  const handleDownload = () => {
    if (!workingPdfBlob) return;
    downloadPdfBlob(workingPdfBlob, fileName);
    toast.success('Đã tải PDF mẫu hồ sơ.');
  };

  const handlePreviewFieldChange = (key: OfficialFormPreviewFieldKey, value: string) => {
    setFieldValues((prev) => sanitizeOfficialFormPreviewFields({ ...prev, [key]: value }));
  };

  const handleResetPreviewFields = () => {
    setFieldValues(sanitizeOfficialFormPreviewFields(initialPreviewFields ?? EMPTY_OFFICIAL_FORM_PREVIEW_FIELDS));
    setWorkingPdfBlob(basePdfBlob);
    toast.success('Đã khôi phục bản xem trước ban đầu.');
  };

  useEffect(() => {
    if (!open || !caseId?.trim()) return;
    let cancelled = false;
    void (async () => {
      try {
        const stored = await getOfficialFormLayout(caseId);
        if (cancelled) return;
        const edits = Array.isArray(stored.layoutEdits) ? stored.layoutEdits : [];
        setInitialLayoutEdits(edits);
        if (edits.length > 0 && basePdfBlob) {
          const overlay = await applyPdfTextLayoutEdits(basePdfBlob, edits);
          if (!cancelled) {
            setWorkingPdfBlob(overlay);
            toast.success('Đã nạp bố cục PDF đã lưu từ máy chủ.');
          }
        }
      } catch (e) {
        if (!cancelled) {
          setInitialLayoutEdits([]);
          const msg = detailFromApiError(e, 'Không tải được bố cục PDF đã lưu.');
          toast.error(msg);
        }
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [open, caseId, basePdfBlob]);

  useEffect(() => {
    if (!open) {
      setInitialLayoutEdits([]);
      return;
    }
    if (!caseId?.trim()) {
      setInitialLayoutEdits([]);
    }
  }, [open, caseId]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent
        className={cn(
          'flex max-h-[90vh] max-w-5xl flex-col gap-0 overflow-hidden p-0 sm:rounded-lg',
          className,
        )}
      >
        <DialogHeader className="space-y-1 border-b border-border px-6 py-4 pr-14 text-left">
          <DialogTitle>Xem trước PDF mẫu hồ sơ</DialogTitle>
          <DialogDescription className="text-xs sm:text-sm space-y-1">
            <span className="block">
              Kiểm tra nội dung trước khi tải. Trình duyệt có thể không hiển thị PDF trong khung bên dưới — dùng « Mở tab
              mới ».
            </span>
            {sourceNote ? <span className="block text-muted-foreground">{sourceNote}</span> : null}
            <span className="block text-muted-foreground">
              Chỉnh dữ liệu trong khung dưới chỉ cập nhật bản xem trước hiện tại (không ghi ngược lên hồ sơ nguồn).
            </span>
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-0 border-b border-border md:grid-cols-[340px_minmax(0,1fr)]">
          <div className="space-y-3 border-b border-border p-4 md:border-b-0 md:border-r">
            <div className="space-y-1">
              <h4 className="text-sm font-medium">Chỉnh trường dữ liệu (xem trước)</h4>
              <p className="text-xs text-muted-foreground">Nhập để phủ chữ lên PDF trong phiên hiện tại.</p>
            </div>
            <div className="space-y-2">
              {OFFICIAL_FORM_PREVIEW_FIELD_DEFS.map((field) => (
                <label key={field.key} className="block space-y-1">
                  <span className="text-xs text-muted-foreground">{field.label}</span>
                  {field.multiline ? (
                    <textarea
                      value={fieldValues[field.key]}
                      onChange={(e) => handlePreviewFieldChange(field.key, e.target.value)}
                      placeholder={field.placeholder}
                      className="min-h-[72px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
                    />
                  ) : (
                    <input
                      type="text"
                      value={fieldValues[field.key]}
                      onChange={(e) => handlePreviewFieldChange(field.key, e.target.value)}
                      placeholder={field.placeholder}
                      className="h-9 w-full rounded-md border border-input bg-background px-3 text-sm"
                    />
                  )}
                </label>
              ))}
            </div>
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="gap-1.5"
              onClick={() => handleResetPreviewFields()}
              disabled={!basePdfBlob}
            >
              <RotateCcw className="h-3.5 w-3.5" aria-hidden />
              Khôi phục bản xem trước ban đầu
            </Button>
          </div>

          <div className="relative min-h-[50vh] bg-muted/30">
            {applyingFieldPreview ? (
              <div className="absolute right-3 top-3 z-10 inline-flex items-center gap-1.5 rounded-md border border-border bg-background/95 px-2.5 py-1 text-xs text-muted-foreground shadow-sm">
                <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden />
                Đang cập nhật xem trước...
              </div>
            ) : null}
            {loading ? (
              <div className="flex min-h-[50vh] flex-col items-center justify-center gap-3 text-muted-foreground">
                <Loader2 className="h-8 w-8 animate-spin" aria-hidden />
                <p className="text-sm">Đang tạo PDF từ mẫu Word…</p>
              </div>
            ) : objectUrl ? (
              <iframe
                title="PDF mẫu hồ sơ"
                src={objectUrl}
                className="absolute inset-0 h-full min-h-[50vh] w-full border-0"
              />
            ) : (
              <div className="flex min-h-[50vh] items-center justify-center text-sm text-muted-foreground">
                Chưa có file PDF.
              </div>
            )}
          </div>
        </div>

        <div className="relative min-h-[18vh] border-b border-border bg-muted/30">
          {loading ? (
            <div className="flex min-h-[18vh] flex-col items-center justify-center gap-3 text-muted-foreground">
              <Loader2 className="h-8 w-8 animate-spin" aria-hidden />
              <p className="text-sm">Đang tạo PDF từ mẫu Word…</p>
            </div>
          ) : (
            <div className="flex min-h-[18vh] items-center justify-center text-xs text-muted-foreground px-4 text-center">
              Mẹo: tiếp tục dùng « Chỉnh bố cục PDF » bên dưới nếu bạn cần tinh chỉnh tọa độ hoặc chèn ghi chú thủ công.
            </div>
          )}
        </div>

        <DialogFooter className="flex-row flex-wrap gap-2 border-t border-border px-6 py-4 sm:justify-between">
          <div className="flex flex-wrap gap-2">
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="gap-1.5"
              disabled={!objectUrl}
              onClick={() => openInNewTab()}
            >
              <ExternalLink className="h-3.5 w-3.5" aria-hidden />
              Mở tab mới
            </Button>
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="gap-1.5"
              disabled={!workingPdfBlob || loading}
              onClick={() => setLayoutEditorOpen(true)}
            >
              <PenLine className="h-3.5 w-3.5" aria-hidden />
              Chỉnh bố cục PDF
            </Button>
          </div>
          <div className="flex flex-wrap gap-2">
            <Button type="button" variant="outline" size="sm" onClick={() => onOpenChange(false)}>
              Đóng
            </Button>
            <Button type="button" size="sm" disabled={!workingPdfBlob || loading} onClick={() => handleDownload()}>
              Tải PDF
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>

      <PdfTextLayoutEditorDialog
        open={layoutEditorOpen}
        onOpenChange={setLayoutEditorOpen}
        pdfBlob={workingPdfBlob}
        fileName={fileName}
        initialEdits={initialLayoutEdits}
        onSaveLayout={
          caseId?.trim()
            ? async (edits, editedPdfBlob) => {
                await saveOfficialFormLayout(caseId, edits, editedPdfBlob, fileName || 'official-form-layout.pdf');
                setInitialLayoutEdits(edits);
                toast.success('Đã lưu bố cục PDF vào máy chủ (PostgreSQL + MinIO).');
              }
            : undefined
        }
        onPdfUpdated={(blob) => {
          setWorkingPdfBlob(blob);
          toast.success('Đã áp dụng chỉnh bố cục chữ lên bản PDF hiện tại.');
        }}
      />
    </Dialog>
  );
}
