import { useEffect, useRef, useState } from "react";
import { Download, FileWarning, RefreshCw, X } from "lucide-react";
import { renderAsync } from "docx-preview";
import { HttpError } from "../../shared/api/errors";
import { AllowedAction } from "../../shared/api/enums";
import type { DocumentSummary } from "../documents/documentTypes";
import { acquirePreview, createPreviewUrl, downloadFile, revokeObjectUrl } from "./fileState";

const PDF_MIME = "application/pdf";
const DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";

function previewError(value: unknown, requestId = "unknown"): HttpError {
  if (value instanceof HttpError) return value;
  return new HttpError({
    httpStatus: 0,
    code: "INTERNAL_ERROR",
    message: value instanceof Error ? value.message : "文件预览失败",
    details: null,
    requestId,
    cause: value,
  });
}

function errorText(error: HttpError, extension: string): string {
  if (error.code === "PREVIEW_UNAVAILABLE" || error.httpStatus === 415) {
    return extension.toLowerCase() === "doc"
      ? "当前DOC格式暂不支持在线预览，请下载原始文件。"
      : "当前文件类型暂不支持在线预览";
  }
  if (error.httpStatus === 403 || error.code === "DOCUMENT_VIEW_FORBIDDEN") return "当前账号无权查看该文件";
  if (error.httpStatus === 404 || error.code === "FILE_NOT_FOUND") return "文件不存在或已被删除";
  if (error.httpStatus === 500) return "预览服务暂时不可用";
  if (error.httpStatus === 0) return "网络连接失败或文档渲染失败";
  return error.message;
}

function sanitizeRenderedContent(container: HTMLElement): void {
  container.querySelectorAll("a").forEach((anchor) => {
    const href = anchor.getAttribute("href") ?? "";
    if (href.trim().toLowerCase().startsWith("javascript:")) anchor.removeAttribute("href");
    if (!/^(https?:|mailto:|#)/i.test(href)) anchor.removeAttribute("href");
    anchor.setAttribute("rel", "noopener noreferrer");
    if (/^https?:/i.test(href)) anchor.setAttribute("target", "_blank");
  });
  container.querySelectorAll("img").forEach((image) => {
    const src = image.getAttribute("src") ?? "";
    if (src && !/^(blob:|data:)/i.test(src)) image.removeAttribute("src");
  });
}

export function FilePreviewModal({ item, onClose, mode = "side" }: {
  item: DocumentSummary;
  onClose: () => void;
  mode?: "side" | "modal";
}) {
  const [url, setUrl] = useState<string | null>(null);
  const [error, setError] = useState<HttpError | null>(null);
  const [loading, setLoading] = useState(true);
  const [downloading, setDownloading] = useState(false);
  const [retryVersion, setRetryVersion] = useState(0);
  const docxContainer = useRef<HTMLDivElement>(null);
  const requestVersion = useRef(0);
  const canDownload = item.allowedActions.includes(AllowedAction.DOWNLOAD);

  useEffect(() => {
    const version = ++requestVersion.current;
    const preview = acquirePreview(item.id, `${item.rowVersion}:${item.updatedAt}:${retryVersion}`);
    let objectUrl: string | null = null;
    let responseRequestId = "unknown";
    setUrl(null);
    setError(null);
    setLoading(true);
    if (docxContainer.current) docxContainer.current.replaceChildren();

    void preview.promise.then(async (result) => {
      responseRequestId = result.requestId;
      if (version !== requestVersion.current) return;
      const mime = (result.contentType || result.blob.type || "").split(";", 1)[0].trim().toLowerCase();
      const extension = item.fileExtension.trim().toLowerCase();
      const expectedMime = extension === "pdf" ? PDF_MIME : extension === "docx" ? DOCX_MIME : null;
      if (!expectedMime || mime !== expectedMime) {
        throw new HttpError({ httpStatus: result.httpStatus, code: "INTERNAL_ERROR", message: "预览文件类型与响应内容不一致", details: null, requestId: result.requestId });
      }
      if (mime === PDF_MIME) {
        objectUrl = createPreviewUrl(result.blob);
        if (version !== requestVersion.current) {
          revokeObjectUrl(objectUrl);
          return;
        }
        setUrl(objectUrl);
        return;
      }
      if (mime !== DOCX_MIME) {
        throw new HttpError({ httpStatus: result.httpStatus, code: "INTERNAL_ERROR", message: "预览文件类型与响应内容不一致", details: null, requestId: result.requestId });
      }
      const buffer = await result.blob.arrayBuffer();
      if (version !== requestVersion.current || !docxContainer.current) return;
      docxContainer.current.replaceChildren();
      await renderAsync(buffer, docxContainer.current, undefined, {
        inWrapper: true,
        ignoreWidth: mode === "side",
        ignoreHeight: true,
        breakPages: true,
        useBase64URL: true,
      });
      if (version !== requestVersion.current || !docxContainer.current) return;
      sanitizeRenderedContent(docxContainer.current);
    }).catch((value: unknown) => {
      if (version === requestVersion.current) setError(previewError(value, responseRequestId));
    }).finally(() => {
      if (version === requestVersion.current) setLoading(false);
    });

    return () => {
      requestVersion.current += 1;
      preview.release();
      revokeObjectUrl(objectUrl);
      if (docxContainer.current) docxContainer.current.replaceChildren();
    };
  }, [item.id, item.rowVersion, item.updatedAt, retryVersion, mode]);

  const download = async () => {
    if (!canDownload || downloading) return;
    setDownloading(true);
    try {
      await downloadFile(item.id, `${item.documentName}.${item.fileExtension || "bin"}`);
    } catch (value) {
      setError(previewError(value));
    } finally {
      setDownloading(false);
    }
  };

  const panel = (
    <aside
      aria-label={mode === "modal" ? "完整文档查看" : "文档右侧预览"}
      className={mode === "modal"
        ? "w-[min(1100px,92vw)] h-[90vh] flex flex-col bg-white shadow-2xl min-h-0"
        : "w-[400px] max-w-[28vw] min-w-[360px] flex-shrink-0 flex flex-col border-l bg-white min-h-0"}
      style={{ borderColor: "rgba(40,118,193,.2)" }}
    >
      <div className="px-4 py-3 flex items-start gap-3 text-white" style={{ background: "#1A5299" }}>
        <div className="min-w-0 flex-1">
          <div className="text-sm font-black truncate" title={item.documentName}>{mode === "modal" ? `文件查看 · ${item.documentName}` : item.documentName}</div>
          <div className="text-[11px] font-bold opacity-70 mt-1">{item.fileExtension?.toUpperCase() || "无扩展名"} · {new Date(item.updatedAt).toLocaleString("zh-CN")}</div>
        </div>
        <button aria-label="关闭预览" onClick={onClose}><X size={17} /></button>
      </div>
      <div className="flex-1 min-h-0 overflow-auto relative" style={{ background: "#EBF4FD" }}>
        {loading && <div className="absolute inset-0 z-10 flex items-center justify-center text-sm font-black" style={{ color: "#1A5299", background: "rgba(235,244,253,.9)" }}><RefreshCw size={15} className="animate-spin mr-2" />正在加载预览…</div>}
        {url && <iframe title={`${item.documentName} PDF预览`} src={url} className="w-full h-full min-h-[560px] border-0" />}
        <div ref={docxContainer} className={`q3-docx-preview min-h-full overflow-auto [&_.docx-wrapper]:!bg-[#d8e8f5] [&_section.docx]:!shadow-sm ${mode === "side" ? "[&_.docx-wrapper]:!p-3 [&_section.docx]:!max-w-full" : "[&_.docx-wrapper]:!p-8"}`} />
        {error && <div className="p-8 text-center" style={{ color: "#1A5299" }}>
          <FileWarning size={38} className="mx-auto mb-3 opacity-60" />
          <div className="text-sm font-black leading-6">{errorText(error, item.fileExtension)}</div>
          {error.requestId && <div className="text-xs font-bold opacity-60 mt-2">错误编号：{error.requestId}</div>}
          {error.httpStatus !== 401 && <button onClick={() => setRetryVersion((value) => value + 1)} className="mt-4 px-3 py-1.5 text-xs font-black border" style={{ borderColor: "#3191eb" }}>重试预览</button>}
        </div>}
      </div>
      {canDownload && <button disabled={downloading} onClick={() => void download()} className="m-3 px-3 py-2 text-sm font-black text-white disabled:opacity-60" style={{ background: "#3191eb" }}><Download size={14} className="inline mr-2" />{downloading ? "正在下载…" : "下载原文件"}</button>}
    </aside>
  );
  if (mode === "modal") {
    return <div className="fixed inset-0 z-[80] flex items-center justify-center" style={{ background: "rgba(26,82,153,.58)" }} onClick={onClose}><div onClick={(event) => event.stopPropagation()}>{panel}</div></div>;
  }
  return panel;
}
