import type { DocPageSetup } from "@/lib/drive/doc-page-setup"

type DocxArchive = Record<string, Uint8Array>

const TWIPS_PER_MM = 1440 / 25.4

function mmToTwips(mm: number): number {
  return Math.round(mm * TWIPS_PER_MM)
}

function decodeXml(bytes: Uint8Array | undefined): string {
  if (!bytes) return ""
  return new TextDecoder().decode(bytes)
}

function encodeXml(text: string): Uint8Array {
  return new TextEncoder().encode(text)
}

function patchSectPr(documentXml: string, pageSetup: DocPageSetup): string {
  const w = mmToTwips(pageSetup.widthMm)
  const h = mmToTwips(pageSetup.heightMm)
  const orient =
    pageSetup.orientation === "landscape" || pageSetup.widthMm > pageSetup.heightMm
      ? ' w:orient="landscape"'
      : ""

  const top = mmToTwips(pageSetup.marginsMm.top)
  const right = mmToTwips(pageSetup.marginsMm.right)
  const bottom = mmToTwips(pageSetup.marginsMm.bottom)
  const left = mmToTwips(pageSetup.marginsMm.left)
  const header = mmToTwips(pageSetup.headerMarginMm ?? pageSetup.marginsMm.top)
  const footer = mmToTwips(pageSetup.footerMarginMm ?? pageSetup.marginsMm.bottom)

  const pgSz = `<w:pgSz w:w="${w}" w:h="${h}"${orient}/>`
  const pgMar = `<w:pgMar w:top="${top}" w:right="${right}" w:bottom="${bottom}" w:left="${left}" w:header="${header}" w:footer="${footer}" w:gutter="0"/>`

  if (/<w:sectPr\b[^>]*>[\s\S]*?<\/w:sectPr>/i.test(documentXml)) {
    return documentXml.replace(/<w:sectPr\b[^>]*>[\s\S]*?<\/w:sectPr>/i, (match) => {
      let inner = match
        .replace(/<w:pgSz\b[^>]*\/?>/gi, "")
        .replace(/<w:pgMar\b[^>]*\/?>/gi, "")
      inner = inner.replace("</w:sectPr>", `${pgSz}${pgMar}</w:sectPr>`)
      return inner
    })
  }

  if (/<w:sectPr\b[^>]*\/>/i.test(documentXml)) {
    return documentXml.replace(
      /<w:sectPr\b[^>]*\/>/i,
      `<w:sectPr>${pgSz}${pgMar}</w:sectPr>`
    )
  }

  return documentXml.replace(/<\/w:body>/i, `<w:sectPr>${pgSz}${pgMar}</w:sectPr></w:body>`)
}

/** Patch page size and margins in a generated DOCX buffer. */
export async function patchDocxPageSetup(
  buffer: ArrayBuffer | Uint8Array,
  pageSetup: DocPageSetup
): Promise<Uint8Array> {
  const { unzipSync, zipSync } = await import("fflate")
  const archive = { ...(unzipSync(new Uint8Array(buffer)) as DocxArchive) }
  const documentPath = "word/document.xml"
  const xml = decodeXml(archive[documentPath])
  if (!xml) return new Uint8Array(buffer)

  archive[documentPath] = encodeXml(patchSectPr(xml, pageSetup))
  return zipSync(archive)
}
