import re
import zipfile
from pathlib import Path

from django.conf import settings
from django.test import SimpleTestCase


class DocxPaginationTest(SimpleTestCase):
    def _read_document_xml(self, docx_path: str) -> str:
        with zipfile.ZipFile(docx_path, "r") as zf:
            return zf.read("word/document.xml").decode("utf-8", errors="replace")

    def _extract_pages_text(self, docx_path: str) -> list[str]:
        """
        Extract per-page plain text by walking body elements and splitting on page breaks.

        Important: we extract w:t texts, so assertions won't be broken by XML tag boundaries.
        """
        import xml.etree.ElementTree as ET

        xml = self._read_document_xml(docx_path)
        ns = {"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"}
        root = ET.fromstring(xml)

        body = root.find("w:body", ns)
        if body is None:
            return []

        pages: list[list[str]] = [[]]

        def has_page_break(el) -> bool:
            for br in el.findall(".//w:br", ns):
                if br.attrib.get(f"{{{ns['w']}}}type") == "page":
                    return True
            return False

        def collect_text(el) -> str:
            ts = [(t.text or "") for t in el.findall(".//w:t", ns)]
            return "".join(ts)

        for child in list(body):
            text = collect_text(child)
            if text:
                pages[-1].append(text)
            if has_page_break(child):
                pages.append([])

        return ["".join(p) for p in pages if "".join(p).strip()]

    def test_render_pages_per_page_totals(self):
        template = str(Path(settings.BASE_DIR) / "print-template.docx")
        out = str(Path(settings.BASE_DIR) / ".tmp_docx" / "rendered-pages-test.docx")
        Path(out).parent.mkdir(parents=True, exist_ok=True)

        from printing.docx_template import render_docx_template_pages

        prefix = "打印-销售单（8*9）."

        # Page 1: two non-empty qty cells => 匹数=2, 总数量=111.11
        page1 = {
            f"{prefix}当前页码": "1",
            f"{prefix}总页数": "2",
            f"{prefix}匹数": "2",
            f"{prefix}总数量": "111.11",
            # Put a couple of quantities too (indices exist 1..72)
            f"{prefix}销售数量1": "11.11",
            f"{prefix}销售数量2": "100",
            # Fill one product line (index 1 exists for product fields)
            f"{prefix}产品名称1": "P1-产品",
            f"{prefix}幅宽1": "150cm",
            f"{prefix}规格1": "规格A",
            f"{prefix}单位1": "米",
        }

        # Page 2: one non-empty qty cell => 匹数=1, 总数量=222.22
        page2 = {
            f"{prefix}当前页码": "2",
            f"{prefix}总页数": "2",
            f"{prefix}匹数": "1",
            f"{prefix}总数量": "222.22",
            f"{prefix}销售数量1": "222.22",
            f"{prefix}产品名称1": "P2-产品",
            f"{prefix}幅宽1": "160cm",
            f"{prefix}规格1": "规格B",
            f"{prefix}单位1": "码",
        }

        render_docx_template_pages(
            template_path=template,
            output_path=out,
            pages_contexts=[page1, page2],
            clear_unresolved=True,
        )

        pages_text = self._extract_pages_text(out)
        self.assertGreaterEqual(len(pages_text), 2, msg="未生成两页文本（可能分页符缺失）")

        p1, p2 = pages_text[0], pages_text[1]
        self.assertIn("P1-产品", p1)
        self.assertIn("111.11", p1)
        self.assertIn("P2-产品", p2)
        self.assertIn("222.22", p2)

        # No raw placeholders should remain (check on plain text concatenation)
        all_text = "".join(pages_text)
        self.assertIsNone(re.search(r"#\{.{1,300}?\}", all_text, flags=re.S))
        self.assertIsNone(re.search(r"(?<!#)\{[^{}\r\n]{1,200}\}", all_text))

