// 거래명세표 / 발주서 등 DOM 영역을 PNG 로 캡처해 공유 또는 다운로드.
// Windows Chrome 에서 html-to-image 의 toPng 가 외부 폰트(Pretendard CDN) 임베드 단계에서
// 실패하는 케이스를 회피하기 위해 skipFonts + cacheBust + jpeg fallback 을 사용한다.

import Swal from "sweetalert2";

interface CaptureShareOptions {
  /** 캡처 대상 DOM (영역 외 버튼은 미리 .js-no-export 클래스로 hide 처리됨) */
  node: HTMLElement;
  /** 저장 파일명 베이스 (확장자 제외) */
  filename: string;
  /** 공유 타이틀 (Web Share API) */
  shareTitle: string;
  /** 공유 텍스트 */
  shareText?: string;
  /** 캡처 시 가로폭 강제 — 모바일 좁은 layout 을 엑셀 가로출력처럼 펼쳐 캡처할 때 사용 (px) */
  forceWidth?: number;
}

export async function captureAndShare({ node, filename, shareTitle, shareText, forceWidth }: CaptureShareOptions): Promise<void> {
  // 거래처에 보낼 이미지에서 내부 정보(.js-no-export)는 잠시 숨긴다.
  const hideEls = node.querySelectorAll<HTMLElement>(".js-no-export");
  const prev: { el: HTMLElement; display: string }[] = [];
  hideEls.forEach((el) => { prev.push({ el, display: el.style.display }); el.style.display = "none"; });

  // forceWidth: 캡처 직전 임시로 node 의 width 를 강제하여 가로 layout 으로 펼친다.
  // 모바일 화면(좁은 viewport)에서 좁게 줄어든 표/품명을 한 줄로 펼치기 위함.
  const widthPrev: {
    width: string; minWidth: string; maxWidth: string;
    paddingLeft: string; paddingRight: string;
  } | null = forceWidth
    ? {
        width: node.style.width,
        minWidth: node.style.minWidth,
        maxWidth: node.style.maxWidth,
        paddingLeft: node.style.paddingLeft,
        paddingRight: node.style.paddingRight,
      }
    : null;
  if (forceWidth) {
    node.style.width = `${forceWidth}px`;
    node.style.minWidth = `${forceWidth}px`;
    node.style.maxWidth = `${forceWidth}px`;
    // 좌우 padding 이 작아도 보기 좋게 — 캡처 직전이라 시각적 영향 없음 (즉시 원복)
    if (!node.style.paddingLeft) node.style.paddingLeft = "24px";
    if (!node.style.paddingRight) node.style.paddingRight = "24px";
    // layout reflow 강제
    void node.offsetWidth;
  }

  let dataUrl: string;
  try {
    const mod = await import("html-to-image");
    const baseOpts = {
      backgroundColor: "#ffffff",
      pixelRatio: 2,
      cacheBust: true,
      // Windows Chrome 에서 외부 CDN 폰트(Pretendard) 임베드 단계가
      // CORS/네트워크 문제로 실패하면 toPng 전체가 깨짐 → 폰트 임베드 스킵
      skipFonts: true,
    } as const;

    try {
      dataUrl = await mod.toPng(node, baseOpts);
    } catch (pngErr) {
      console.warn("[capture] toPng 실패, toJpeg 로 재시도:", pngErr instanceof Error ? pngErr.message : pngErr);
      dataUrl = await mod.toJpeg(node, { ...baseOpts, quality: 0.95 });
    }
  } catch (err) {
    // 복원 후 에러 표시
    prev.forEach((p) => { p.el.style.display = p.display; });
    const msg = err instanceof Error ? err.message : String(err);
    console.error("[capture] 캡처 자체 실패:", err);
    await Swal.fire({
      icon: "error",
      title: "이미지 캡처 실패",
      html: `<div class="text-left text-xs">${msg}</div><br><span class="text-xs text-slate-500">브라우저 콘솔(F12)에 자세한 로그가 있습니다.</span>`,
    });
    return;
  } finally {
    // 캡처 끝나면 (성공/실패 무관) 숨겼던 요소 복원
    prev.forEach((p) => { p.el.style.display = p.display; });
    if (widthPrev) {
      node.style.width = widthPrev.width;
      node.style.minWidth = widthPrev.minWidth;
      node.style.maxWidth = widthPrev.maxWidth;
      node.style.paddingLeft = widthPrev.paddingLeft;
      node.style.paddingRight = widthPrev.paddingRight;
    }
  }

  // 공유 또는 다운로드 단계
  try {
    const ext = dataUrl.startsWith("data:image/jpeg") ? "jpg" : "png";
    const mime = ext === "jpg" ? "image/jpeg" : "image/png";
    const blob = await (await fetch(dataUrl)).blob();
    const file = new File([blob], `${filename}.${ext}`, { type: mime });

    // Web Share API (모바일 + 일부 데스크톱) - files 공유 지원 시
    const navAny = navigator as Navigator & { canShare?: (data: { files: File[] }) => boolean };
    if (navAny.canShare && navAny.canShare({ files: [file] })) {
      try {
        await navigator.share({ files: [file], title: shareTitle, text: shareText ?? "" });
        return;
      } catch (shareErr) {
        // 사용자가 취소했거나 share API 실패 → 다운로드로 폴백
        const name = (shareErr as Error)?.name;
        if (name === "AbortError") return; // 사용자 취소면 그냥 종료
        console.warn("[capture] navigator.share 실패, 다운로드로 폴백:", shareErr);
      }
    }

    // 폴백: 다운로드
    const a = document.createElement("a");
    a.href = dataUrl;
    a.download = `${filename}.${ext}`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    Swal.fire({
      icon: "success",
      title: "이미지 저장 완료",
      text: "다운로드한 이미지를 카톡 등에 첨부해 보내세요.",
      timer: 1500,
      showConfirmButton: false,
    });
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    console.error("[capture] 공유/다운로드 단계 실패:", err);
    Swal.fire({
      icon: "error",
      title: "이미지 공유 실패",
      html: `<div class="text-left text-xs">${msg}</div>`,
    });
  }
}
