type RecoveryDocumentKey =
  | 'all_application'
  | 'creditors_csv'
  | 'creditors'
  | 'assets'
  | 'income_expense'
  | 'statement'
  | 'repayment_plan'
  | 'prohibition'
  | 'suspension'
  | 'copy_submission'
  | 'filing_certificate'
  | 'power_of_attorney'
  | 'trustee_debt'
  | 'confirmation'

const PAGE_BREAK_MARKER_SELECTOR = '.fincure-page-break, .pdf-page-break-marker'
const AUTO_PAGE_BREAK_MARKER_SELECTOR = '.fincure-page-break[data-auto-page-break="true"], .pdf-page-break-marker[data-auto-page-break="true"]'
const PREVIEW_PAGE_BREAK_LABEL = '------------------- [수정하거나 지우지 마세요] 이 부분은 인쇄할때 페이지를 구분합니다. -------------------'
const PREVIEW_PAGE_CONTAINER_CLASS = 'fincure-preview-page'
const PRINT_SECTION_CLASS = 'fincure-print-section'
const PAGE_BREAK_SCREEN_LABEL_HTML = `<span class="fincure-page-break-screen-only" style="position:absolute;top:0;left:50%;transform:translate(-50%, -55%);padding:0 12px;background:#ffffff;color:#dc2626;font-size:12px;font-weight:700;line-height:1.4;white-space:nowrap;">${PREVIEW_PAGE_BREAK_LABEL}</span>`
const PAGE_BREAK_SCREEN_STYLE = 'display:block;width:100%;height:1px;min-height:1px;margin:36px 0 48px;padding:0;border:0;border-top:1px dashed #ef4444;overflow:visible;visibility:visible;position:relative;pointer-events:none;break-before:auto;page-break-before:auto;'
const MANUAL_PAGE_BREAK_MARKER_HTML = `<div class="fincure-page-break" data-page-break="manual" aria-hidden="true" style="${PAGE_BREAK_SCREEN_STYLE}">${PAGE_BREAK_SCREEN_LABEL_HTML}</div>`
const AUTO_PAGE_BREAK_MARKER_HTML = `<div class="fincure-page-break" data-page-break="auto" data-auto-page-break="true" aria-hidden="true" style="${PAGE_BREAK_SCREEN_STYLE}">${PAGE_BREAK_SCREEN_LABEL_HTML}</div>`
const LEGACY_PAGE_BREAK_MARKER_PATTERN = /<p style='page-break-before:always'><b style='color:#ff0000;text-align:center;'>------------------- \[수정하거나 지우지 마세요\] 이 부분은 인쇄할때 페이지를 구분합니다\. -------------------<\/b><br style='height:0; line-height:0'>/gi
const LEGACY_AUTO_PAGE_BREAK_DIV_PATTERN = /<div(?=[^>]*class=(['"])[^'"]*pdf-page-break-marker[^'"]*\1)(?=[^>]*data-auto-page-break=(['"])true\2)[^>]*><\/div>/gi
const LEGACY_PAGE_BREAK_DIV_PATTERN = /<div(?=[^>]*class=(['"])[^'"]*pdf-page-break-marker[^'"]*\1)[^>]*><\/div>/gi
const EMPTY_AUTO_PAGE_BREAK_PATTERN = /<div(?=[^>]*class=(['"])[^'"]*fincure-page-break[^'"]*\1)(?=[^>]*data-auto-page-break=(['"])true\2)[^>]*><\/div>/gi
const EMPTY_MANUAL_PAGE_BREAK_PATTERN = /<div(?=[^>]*class=(['"])[^'"]*fincure-page-break[^'"]*\1)(?![^>]*data-auto-page-break=)[^>]*><\/div>/gi

const normalizeVisibleWhitespaceEntities = (html: string) =>
  String(html || '')
    .replace(/&(amp|#38);nbsp;/gi, '&nbsp;')
    .replace(/&(amp|#38);#160;/gi, '&#160;')
    .replace(/&(amp|#38);ensp;/gi, '&ensp;')
    .replace(/&(amp|#38);emsp;/gi, '&emsp;')

const normalizePageBreakMarkup = (html: string) =>
  String(html || '')
    .replace(LEGACY_PAGE_BREAK_MARKER_PATTERN, MANUAL_PAGE_BREAK_MARKER_HTML)
    .replace(LEGACY_AUTO_PAGE_BREAK_DIV_PATTERN, AUTO_PAGE_BREAK_MARKER_HTML)
    .replace(LEGACY_PAGE_BREAK_DIV_PATTERN, MANUAL_PAGE_BREAK_MARKER_HTML)
    .replace(EMPTY_AUTO_PAGE_BREAK_PATTERN, AUTO_PAGE_BREAK_MARKER_HTML)
    .replace(EMPTY_MANUAL_PAGE_BREAK_PATTERN, MANUAL_PAGE_BREAK_MARKER_HTML)

export const usePdfGenerator = () => {
  const {
    createCreditorsCsv,
    getDocumentDefinition,
    getDocumentHtml,
    fetchCaseInfo,
    loadDocumentContext,
    sanitizeFileName
  } = useRecoveryDocumentForms()

  const ensureClient = () => {
    if (!process.client) {
      throw new Error('브라우저 환경에서만 사용할 수 있습니다.')
    }
  }

  const downloadBlob = (blob: Blob, fileName: string) => {
    ensureClient()
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = fileName
    document.body.appendChild(link)
    link.click()
    link.remove()
    window.URL.revokeObjectURL(url)
  }

  const commercePrintCss = `
    body {
      margin: 0;
      background: #d7dde8;
      color: #000;
      font-family: 'Batang', 'BatangChe', 'Nanum Myeongjo', serif;
    }
    #smart_edit_print,
    #smart_edit_print *,
    .preview-paper,
    .preview-paper * {
      font-family: 'Batang', 'BatangChe', 'Nanum Myeongjo', serif !important;
    }
    .preview-toolbar {
      position: sticky;
      top: 0;
      z-index: 20;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 16px;
      padding: 14px 20px;
      background: rgba(28, 35, 49, 0.92);
      color: #fff;
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
      backdrop-filter: blur(8px);
    }
    .preview-toolbar-title {
      font-size: 15px;
      font-weight: 700;
      letter-spacing: -0.2px;
    }
    .preview-toolbar-actions {
      display: flex;
      align-items: center;
      gap: 8px;
    }
    .preview-button {
      border: 1px solid rgba(255, 255, 255, 0.2);
      background: #ffffff;
      color: #111827;
      border-radius: 10px;
      padding: 10px 16px;
      font-size: 13px;
      font-weight: 700;
      cursor: pointer;
    }
    .preview-button.primary {
      background: #ef4444;
      border-color: #ef4444;
      color: #fff;
    }
    .preview-shell {
      padding: 28px 0 44px;
    }
    .preview-paper {
      width: 820px;
      margin: 0 auto;
      background: #fff;
      box-shadow: 0 18px 40px rgba(15, 23, 42, 0.18);
      padding: 30px 34px 40px;
    }
    .fincure-page-break,
    .pdf-page-break-marker {
      display: block;
      width: 100%;
      height: 1px !important;
      min-height: 1px !important;
      margin: 36px 0 48px !important;
      padding: 0 !important;
      border: 0 !important;
      border-top: 1px dashed #ef4444 !important;
      overflow: visible !important;
      visibility: visible !important;
      position: relative;
      pointer-events: none;
      break-before: auto;
      page-break-before: auto;
    }
    .fincure-page-break::before,
    .pdf-page-break-marker::before {
      content: ${JSON.stringify(PREVIEW_PAGE_BREAK_LABEL)};
      position: absolute;
      top: 0;
      left: 50%;
      transform: translate(-50%, -55%);
      padding: 0 12px;
      background: #ffffff;
      color: #dc2626;
      font-size: 12px;
      font-weight: 700;
      line-height: 1.4;
      white-space: nowrap;
    }
    .fincure-page-break-screen-only {
      position: absolute;
      top: 0;
      left: 50%;
      transform: translate(-50%, -55%);
      padding: 0 12px;
      background: #ffffff;
      color: #dc2626;
      font-size: 12px;
      font-weight: 700;
      line-height: 1.4;
      white-space: nowrap;
    }
    .fincure-page-break[data-auto-page-break="true"],
    .pdf-page-break-marker[data-auto-page-break="true"] {
      margin-top: 42px !important;
      margin-bottom: 54px !important;
    }
    .${PREVIEW_PAGE_CONTAINER_CLASS} {
      min-height: var(--fincure-preview-page-height, 0px);
      box-sizing: border-box;
      display: block;
    }
    .${PRINT_SECTION_CLASS} {
      display: block;
      width: 100%;
      box-sizing: border-box;
      break-inside: avoid-page;
      page-break-inside: avoid;
    }
    @page {
      size: A4 portrait;
      margin: 10mm;
    }
    @media print {
      body {
        background: #fff;
      }
      .preview-toolbar {
        display: none !important;
      }
      .preview-shell {
        padding: 0;
      }
      .preview-paper {
        width: auto;
        margin: 0;
        box-shadow: none;
        padding: 0;
      }
      .fincure-page-break,
      .pdf-page-break-marker {
        height: 0 !important;
        min-height: 0 !important;
        margin: 0 !important;
        border: 0 !important;
        display: block !important;
        overflow: hidden !important;
        visibility: hidden !important;
        break-before: page !important;
        page-break-before: always !important;
      }
      .fincure-page-break::before,
      .pdf-page-break-marker::before {
        display: none !important;
      }
      .fincure-page-break-screen-only {
        display: none !important;
      }
      .${PREVIEW_PAGE_CONTAINER_CLASS} {
        min-height: 0 !important;
      }
      .${PRINT_SECTION_CLASS} {
        break-inside: avoid-page;
        page-break-inside: avoid;
      }
      .printhidden {
        visibility: hidden !important;
      }
    }
  `

  const buildPrintWindowHtml = (
    html: string,
    title: string,
    documentKey: RecoveryDocumentKey
  ) => {
    const normalizedHtml = normalizePageBreakMarkup(normalizeVisibleWhitespaceEntities(html))
    const parsed = new DOMParser().parseFromString(normalizedHtml, 'text/html')
    parsed.head.querySelectorAll('base').forEach((node) => node.remove())
    const headContent = parsed.head.innerHTML
    const bodyContent = parsed.body.innerHTML
    const baseHref = process.client ? `${window.location.origin}/` : '/'
    const autoPaginateScript = `
  <script>
    (() => {
      const previewPageClass = ${JSON.stringify(PREVIEW_PAGE_CONTAINER_CLASS)};
      const autoMarkerSelector = ${JSON.stringify(AUTO_PAGE_BREAK_MARKER_SELECTOR)};
      const unwrapPreviewPages = (root) => {
        Array.from(root.querySelectorAll('.' + previewPageClass))
          .reverse()
          .forEach((page) => {
            while (page.firstChild) {
              page.parentNode?.insertBefore(page.firstChild, page);
            }
            page.remove();
          });
      };
      const normalize = () => {
        const root = document.getElementById('smart_edit_print');
        if (!root) return;
        unwrapPreviewPages(root);
        root.querySelectorAll(autoMarkerSelector).forEach((node) => node.remove());
      };
      window.__normalizeForPrint = normalize;
      window.addEventListener('load', () => requestAnimationFrame(() => normalize()), { once: true });
      window.addEventListener('beforeprint', normalize);
    })();
  </script>`
    const readinessScript = `
  <script>
    (() => {
      const markReady = () => {
        window.__printReady = true;
        window.dispatchEvent(new Event('fincure-print-ready'));
      };
      const waitForStylesheets = () => Promise.all(
        Array.from(document.querySelectorAll('link[rel="stylesheet"]')).map((link) => new Promise((resolve) => {
          if (link.sheet) {
            resolve();
            return;
          }

          let settled = false;
          const finish = () => {
            if (settled) return;
            settled = true;
            link.removeEventListener('load', finish);
            link.removeEventListener('error', finish);
            resolve();
          };

          link.addEventListener('load', finish, { once: true });
          link.addEventListener('error', finish, { once: true });
          window.setTimeout(finish, 1500);
        }))
      );

      const waitForImages = () => Promise.all(
        Array.from(document.images).map((image) => new Promise((resolve) => {
          if (image.complete) {
            resolve();
            return;
          }

          image.addEventListener('load', () => resolve(), { once: true });
          image.addEventListener('error', () => resolve(), { once: true });
        }))
      );

      const waitForFonts = () => document.fonts
        ? document.fonts.ready.catch(() => undefined)
        : Promise.resolve();

      const waitForFrames = () => new Promise((resolve) => {
        requestAnimationFrame(() => requestAnimationFrame(resolve));
      });

      window.__printReady = false;
      window.addEventListener('load', async () => {
        try {
          await Promise.all([waitForStylesheets(), waitForImages(), waitForFonts()]);
          if (typeof window.__normalizeForPrint === 'function') {
            window.__normalizeForPrint();
          }
          await waitForFrames();
        } finally {
          markReady();
        }
      }, { once: true });
    })();
  </script>`

    return `<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>${title}</title>
  <base href="${baseHref}" />
  ${headContent}
  <style>${commercePrintCss}</style>
</head>
<body>
  <div class="preview-toolbar printhidden">
    <div class="preview-toolbar-title">${title}</div>
    <div class="preview-toolbar-actions">
      <button type="button" class="preview-button" onclick="window.close()">닫기</button>
      <button type="button" class="preview-button primary" onclick="window.print()">인쇄하기</button>
    </div>
  </div>
  <div class="preview-shell">
    <div class="preview-paper">
      <div id="smart_edit_print">${bodyContent}</div>
    </div>
  </div>
  ${autoPaginateScript}
  ${readinessScript}
</body>
</html>`
  }

  const buildPrintWindowLoadingHtml = (title: string) => `<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>${title}</title>
  <style>
    body {
      margin: 0;
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      background: #f3f4f6;
      color: #111827;
      font-family: 'Batang', 'BatangChe', 'Nanum Myeongjo', serif;
    }
    .loading-card {
      padding: 20px 24px;
      border-radius: 14px;
      background: #ffffff;
      box-shadow: 0 16px 40px rgba(15, 23, 42, 0.12);
      font-size: 14px;
      font-weight: 700;
      letter-spacing: -0.2px;
    }
  </style>
</head>
<body>
  <div class="loading-card">문서를 준비하는 중입니다...</div>
</body>
</html>`

  const openPrintWindow = (title: string) => {
    ensureClient()
    const printWindow = window.open('', '_blank', 'width=1120,height=900,scrollbars=yes')
    if (!printWindow) {
      throw new Error('팝업이 차단되었습니다.')
    }

    printWindow.document.open()
    printWindow.document.write(buildPrintWindowLoadingHtml(title))
    printWindow.document.close()
    return printWindow
  }

  const requestRenderedPdf = async (html: string, fileName: string) => {
    ensureClient()

    const response = await fetch('/api/render-recovery-document-pdf', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        html: normalizeVisibleWhitespaceEntities(html),
        fileName
      })
    })

    if (!response.ok) {
      const message = await response.text().catch(() => '')
      throw new Error(message || 'PDF 렌더링에 실패했습니다.')
    }

    return response.blob()
  }

  const printHtml = (
    printWindow: Window,
    html: string,
    title: string,
    documentKey: RecoveryDocumentKey,
    autoPrint = false
  ) => {
    ensureClient()

    printWindow.document.open()
    printWindow.document.write(buildPrintWindowHtml(html, title, documentKey))
    printWindow.document.close()
    printWindow.focus()

    if (autoPrint) {
      const targetWindow = printWindow as Window & {
        __printReady?: boolean
      }

      const triggerPrint = () => {
        if (targetWindow.closed) return
        targetWindow.focus()
        targetWindow.print()
      }

      const waitForReady = () => new Promise<void>((resolve) => {
        if (targetWindow.__printReady) {
          resolve()
          return
        }

        let settled = false
        const finish = () => {
          if (settled) return
          settled = true
          targetWindow.removeEventListener('fincure-print-ready', finish as EventListener)
          resolve()
        }

        targetWindow.addEventListener('fincure-print-ready', finish as EventListener, { once: true })

        let elapsed = 0
        const poll = () => {
          if (targetWindow.closed) {
            finish()
            return
          }

          if (targetWindow.__printReady) {
            finish()
            return
          }

          elapsed += 50
          if (elapsed >= 5000) {
            finish()
            return
          }

          window.setTimeout(poll, 50)
        }

        poll()
      })

      void waitForReady().then(() => {
        window.setTimeout(triggerPrint, 150)
      })
    }
  }

  const generateRecoveryDocumentPdf = async (caseId: number, documentKey: RecoveryDocumentKey) => {
    if (documentKey === 'creditors_csv') {
      const context = await loadDocumentContext(caseId)
      const csv = createCreditorsCsv(context.pages)
      const applicantName = sanitizeFileName(context.caseInfo?.applicant_name || 'document')
      const definition = getDocumentDefinition(documentKey)
      downloadBlob(
        new Blob([csv], { type: 'text/csv;charset=utf-8;' }),
        `${definition.fileBaseName}_${applicantName}.csv`
      )
      return { success: true }
    }

    const definition = getDocumentDefinition(documentKey)
    const html = await getDocumentHtml(caseId, documentKey)
    const caseInfo = await fetchCaseInfo(caseId)
    const applicantName = sanitizeFileName(caseInfo?.applicant_name || 'document')
    const fileTitle = `${definition.fileBaseName}_${applicantName}`
    const renderedPdf = await requestRenderedPdf(
      buildPrintWindowHtml(html, fileTitle, documentKey),
      fileTitle
    )
    downloadBlob(renderedPdf, `${fileTitle}.pdf`)
    return { success: true }
  }

  const printRecoveryDocument = async (caseId: number, documentKey: RecoveryDocumentKey) => {
    const definition = getDocumentDefinition(documentKey)
    const printWindow = openPrintWindow(definition.manualLabel)

    try {
      const html = await getDocumentHtml(caseId, documentKey)
      printHtml(printWindow, html, definition.manualLabel, documentKey)
      return { success: true }
    } catch (error) {
      if (!printWindow.closed) {
        printWindow.close()
      }
      throw error
    }
  }

  const printAllDocuments = async (caseId: number) => {
    return printRecoveryDocument(caseId, 'all_application')
  }

  return {
    generateAssetsListPdf: (caseId: number) => generateRecoveryDocumentPdf(caseId, 'assets'),
    generateCreditorsListPdf: (caseId: number) => generateRecoveryDocumentPdf(caseId, 'creditors'),
    generateFullApplicationPdf: (caseId: number) => generateRecoveryDocumentPdf(caseId, 'all_application'),
    generateIncomeExpensePdf: (caseId: number) => generateRecoveryDocumentPdf(caseId, 'income_expense'),
    generateRecoveryDocumentPdf,
    printAllDocuments,
    printRecoveryDocument
  }
}
