"""
将 invoice_summary.csv 填入「易耗品、出库单.doc」表格。

仅写入表格数据单元格，保留原模板字体、边框与版式。
"""

from __future__ import annotations

import argparse
import re
import shutil
from datetime import date
from pathlib import Path
from typing import Any

from .. import get_logger
from ..config import load_config
from ..doc.invoice import load_invoice_csv

log = get_logger("fill_consumable_doc")

CONSUMABLE_DOC_FILENAME = "易耗品、出库单.doc"

# Word COM 常量
WD_CHARACTER = 1

# 表格统一字体：宋体、五号（10.5 磅）
TABLE_FONT_NAME = "宋体"
TABLE_FONT_SIZE = 10.5


def _split_name_spec(left: str) -> tuple[str, str]:
    m = re.search(r"(\S+一批)\s*$", left)
    if m:
        return m.group(1), left[: m.start()].strip()
    parts = left.split(" ", 1)
    if len(parts) == 2:
        return parts[0], parts[1]
    return left, ""


def parse_spec_model(spec: str) -> dict[str, str]:
    spec = (spec or "").strip()
    if " 个 " not in spec:
        return {
            "product_name": spec,
            "spec": "",
            "unit": "",
            "qty": "",
            "unit_price": "",
        }

    left, right = spec.split(" 个 ", 1)
    product_name, model_spec = _split_name_spec(left.strip())
    tokens = right.split()

    qty = ""
    unit_price = ""
    if len(tokens) >= 4 and re.fullmatch(r"\d+(?:\.\d+)?", tokens[0]):
        qty, unit_price = tokens[0], tokens[1]
    elif tokens and re.fullmatch(r"\d+(?:\.\d+)?", tokens[0]):
        qty, unit_price = "1", tokens[0]

    return {
        "product_name": product_name,
        "spec": model_spec,
        "unit": "个",
        "qty": qty,
        "unit_price": unit_price,
    }


def _format_money(value: str | float) -> str:
    """单价、金额：固定保留两位小数。"""
    if value is None or value == "":
        return ""
    try:
        num = float(value)
    except (TypeError, ValueError):
        return str(value)
    return f"{num:.2f}"


def _today_cn_date() -> str:
    """当前日期，格式：2026年5月26日"""
    today = date.today()
    return f"{today.year}年{today.month}月{today.day}日"


def _apply_font(rng: Any) -> None:
    """将范围字体设为宋体五号（含数字与英文）。"""
    font = rng.Font
    font.Name = TABLE_FONT_NAME
    font.NameFarEast = TABLE_FONT_NAME
    font.NameAscii = TABLE_FONT_NAME
    font.NameOther = TABLE_FONT_NAME
    font.NameBi = TABLE_FONT_NAME
    font.Size = TABLE_FONT_SIZE


def _set_cell_value(cell: Any, text: str) -> None:
    """写入单元格正文（不含末尾单元格标记）。"""
    rng = cell.Range
    rng.MoveEnd(WD_CHARACTER, -1)
    rng.Text = "" if text is None else str(text)
    _apply_font(rng)


def _normalize_table_font(tbl: Any) -> None:
    """填写完成后统一整张表的字体。"""
    for row in tbl.Rows:
        for cell in row.Cells:
            rng = cell.Range
            rng.MoveEnd(WD_CHARACTER, -1)
            _apply_font(rng)


def _replace_date_in_doc(doc: Any, new_date: str) -> None:
    """仅替换表头段落中的日期文字，不改动段落其余部分。"""
    if not new_date:
        return
    try:
        para = doc.Paragraphs(3)
    except Exception:
        return
    rng = para.Range
    text = rng.Text.replace("\r", "").replace("\x07", "")
    m = re.search(r"\d{4}年\d{1,2}月\d{1,2}日", text)
    if not m:
        return
    start = rng.Start + m.start()
    end = rng.Start + m.end()
    doc.Range(Start=start, End=end).Text = new_date


def fill_consumable_doc(
    csv_path: str | Path,
    doc_path: str | Path,
    config: dict[str, Any] | None = None,
    backup: bool = True,
) -> Path:
    csv_path = Path(csv_path)
    doc_path = Path(doc_path)
    if config is None:
        config = load_config()

    invoices = load_invoice_csv(csv_path.parent / "invoice_summary.csv") or []

    if backup:
        bak = doc_path.with_suffix(doc_path.suffix + ".bak")
        shutil.copy2(doc_path, bak)

    import pythoncom
    import win32com.client

    pythoncom.CoInitialize()
    try:
        word = win32com.client.Dispatch("Word.Application")
        word.Visible = False
        word.DisplayAlerts = 0
        doc = word.Documents.Open(str(doc_path.resolve()))

        try:
            _replace_date_in_doc(doc, _today_cn_date())

            tbl = doc.Tables(1)
            storage = config.get("consumable_storage", "躬行楼 C205")

            for i, inv in enumerate(invoices):
                row_idx = i + 2
                if row_idx > tbl.Rows.Count:
                    break

                parsed = parse_spec_model(str(inv.get("spec_model", "")))
                # 当规格型号为空时，从项目名称提取产品信息
                if not parsed["product_name"]:
                    item_name = str(inv.get("item_name", ""))
                    # 去除 "*分类*" 前缀（如 "*电子工业设备*元件盒" -> "元件盒"）
                    if "*" in item_name:
                        item_name = item_name.split("*")[-1].strip()
                    parsed["product_name"] = item_name

                card_amount_raw = inv.get("card_amount") or 0
                card_amount: float = float(str(card_amount_raw).replace(",", ""))
                qty_str = parsed["qty"]
                qty_val = int(qty_str) if qty_str and qty_str.isdigit() else 0

                # 金额填写刷卡金额，单价由刷卡金额反算
                amount = _format_money(card_amount)
                unit_price = _format_money(card_amount / qty_val) if qty_val > 0 else _format_money(card_amount)

                # 数量：去掉前导零；若无数量则默认为 1
                qty = str(qty_val) if qty_val > 0 else "1"

                values = [
                    str(inv.get("index", i + 1)),
                    parsed["product_name"],
                    parsed["spec"],
                    parsed["unit"],
                    qty,
                    unit_price,
                    amount,
                    "",  # 购货人签字 — 保持空白
                    storage,
                    "",  # 领用人签字 — 保持空白
                    "",  # 备注 — 保持空白，避免撑破版式
                ]

                for col_idx, val in enumerate(values, start=1):
                    _set_cell_value(tbl.Cell(row_idx, col_idx), str(val))

            _normalize_table_font(tbl)

            doc.Save()
        finally:
            doc.Close()
            word.Quit()
    finally:
        pythoncom.CoUninitialize()

    return doc_path


def fill_consumable_from_template(
    csv_path: str | Path,
    template_path: str | Path,
    output_path: str | Path,
    config: dict[str, Any] | None = None,
) -> Path:
    """从模板复制并填写出库单（Web 会话每次从模板重新生成）。"""
    template_path = Path(template_path)
    output_path = Path(output_path)
    if not template_path.exists():
        raise FileNotFoundError(f"出库单模板不存在: {template_path}")
    shutil.copy2(template_path, output_path)
    return fill_consumable_doc(csv_path, output_path, config=config, backup=False)


def main() -> None:
    root = Path(__file__).resolve().parents[1]
    parser = argparse.ArgumentParser(description="将发票 CSV 填入易耗品出库单")
    parser.add_argument("--csv", default=str(root / "invoice_summary.csv"))
    parser.add_argument("--doc", default=str(root / "易耗品、出库单.doc"))
    parser.add_argument("--config", default=str(root / "scripts" / "data" / "config.json"))
    parser.add_argument("--no-backup", action="store_true")
    args = parser.parse_args()

    cfg = None
    if Path(args.config).exists():
        import json

        with open(args.config, encoding="utf-8") as f:
            cfg = {**load_config(), **json.load(f)}
    out = fill_consumable_doc(args.csv, args.doc, config=cfg, backup=not args.no_backup)
    print(f"已填写并保存: {out}")


if __name__ == "__main__":
    main()
