#!/usr/bin/env python3
from __future__ import annotations

import argparse
import importlib.util
from pathlib import Path

from docx import Document
from docx.enum.section import WD_SECTION
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK


HERE = Path(__file__).resolve().parent
BASE_SCRIPT = HERE / "build_requirements_doc.py"
spec = importlib.util.spec_from_file_location("onecard_doc_base", BASE_SCRIPT)
base = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(base)


def cover(doc: Document) -> None:
    for _ in range(4):
        base.style_paragraph(doc.add_paragraph(), after=0)
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    base.style_paragraph(p, after=10, line=1.0)
    base.add_text(p, "一卡通接口与 Android/Linux SDK", bold=True, color=base.ORANGE, size=23)
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    base.style_paragraph(p, after=20, line=1.0)
    base.add_text(p, "对接需求说明（精简版）", bold=True, color=base.DARK, size=21)
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    base.style_paragraph(p, after=28)
    base.add_text(p, "请一卡通厂商确认并提供现有接口资料，以及 Android 11 SDK 或可用的 Linux SDK", color=base.MID, size=11)
    base.add_table(doc, ["项目", "内容"], [
        ["文档版本", "V1.1（精简评审稿）"],
        ["核心需求", "一、补齐现有老接口资料；二、提供 Android 11 SDK，或明确可落地的 Linux SDK。"],
        ["目标设备", "智慧食堂 Android 11 设备，需连接一卡通读卡器、PSAM并完成读卡、扣款和人员查询。"],
    ], [1800, 6506], font_size=9.5)
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    base.style_paragraph(p, before=18, after=0)
    base.add_text(p, "康比特数字体育科技", bold=True, color=base.DARK, size=12)
    p.add_run().add_break(WD_BREAK.PAGE)


def build(template: Path, output: Path) -> None:
    doc = Document(str(template))
    base.configure_styles(doc)
    doc.core_properties.title = "一卡通接口与 Android/Linux SDK 对接需求说明（精简版）"
    doc.core_properties.subject = "一卡通老接口资料与 Android/Linux SDK 索取需求"
    doc.core_properties.author = "康比特数字体育科技"
    doc.core_properties.last_modified_by = "康比特数字体育科技"
    section = doc.sections[0]
    section.start_type = WD_SECTION.NEW_PAGE
    for paragraph in section.header.paragraphs:
        for run in paragraph.runs:
            original_size = run.font.size.pt if run.font.size else 12
            base.set_font(run, name=base.BODY_FONT, size=original_size, bold=bool(run.bold), color=base.DARK)
    cover(doc)

    base.add_heading(doc, "我们的需求", 1)
    base.add_callout(doc, "一句话说明", "请贵方提供现有一卡通接口的完整资料，并优先提供可在 Android 11 上运行的 SDK；如只有 Linux SDK，请明确它是否兼容 Android，或者是否需要单独部署 Linux 中转设备。")
    base.add_body(doc, "我们不要求把现有 Windows DLL 强行转换成 Android .so。我们需要的是厂商正式支持、可维护、能连接读卡器和PSAM的接口或SDK。")

    base.add_heading(doc, "1. 现有老接口资料", 1)
    base.add_body(doc, "请先把当前 Windows 版本的一卡通接口资料补齐，作为现有系统功能和字段口径的基线。")
    base.add_table(doc, ["需要提供", "具体内容", "用途"], [
        ["原接口程序", "Change.dll、对应版本号、发布日期和SHA-256；如有Change.lib、Change.h也请一并提供。", "确认接口版本和调用方式。"],
        ["函数说明", "完整说明打开/关闭读卡器、寻卡、读卡、扣款、连接中心、上传记录、人员、部门和黑名单等接口。", "对应现有16个DLL导出函数。"],
        ["数据结构", "CustomerInfo、UPLOADINFO、人员、部门等结构体的字段类型、长度、对齐、编码和单位。", "避免金额、PSAM、TAC和opCount错位。"],
        ["返回码", "每个接口的成功码、失败码、卡状态、钱包类型及异常处理建议。", "统一Android/Linux端错误处理。"],
        ["运行依赖", "读卡器和PSAM驱动、注册工具、SysInit.dat/授权方式、依赖DLL及安装顺序。", "保证现场能真正打开设备。"],
        ["配置说明", "Change.set、WebService、应用ID、终端ID、科目ID、混淆参数的含义和配置方法。", "完成中心连接和消费上传。"],
        ["Demo和测试", "只读、扣款、上传和人员查询Demo；提供测试卡、测试环境或联调方式。", "用于双方快速验证。"],
    ], [1700, 4700, 1906], font_size=8.7)
    base.add_callout(doc, "最低要求", "如果不能提供DLL源码，至少需要提供正式头文件、结构体定义、调用约定、接口文档、错误码和可运行Demo。", fill=base.LIGHT_BLUE)

    base.add_heading(doc, "2. Android SDK 或 Linux SDK", 1)
    base.add_heading(doc, "2.1 首选：Android 11 SDK", 2)
    base.add_body(doc, "优先请提供可以直接集成到现有 Android 11 智慧食堂应用中的厂商SDK。")
    base.add_bullets(doc, [
        "支持Android 11，并明确支持的CPU架构；目标设备通常优先需要arm64-v8a。",
        "提供.aar/.jar、Android NDK编译的.so、JNI或Kotlin/Java调用说明。",
        "提供目标读卡器和PSAM在Android上的驱动、权限、USB/串口/HID连接方法。",
        "至少支持初始化、设备状态、寻卡、读卡、扣款、写后余额和opCount、中心上传、人员查询。",
        "提供Demo工程、接口文档、错误码、授权方式、SDK版本和SHA-256。",
    ])

    base.add_heading(doc, "2.2 备选：Linux SDK", 2)
    base.add_body(doc, "如果贵方没有Android SDK，也可以提供Linux SDK，但必须明确运行环境。")
    base.add_table(doc, ["Linux SDK类型", "是否可用", "我们的要求"], [
        ["Android NDK/Bionic版本", "可直接评估集成Android", "提供目标ABI的.so、头文件、JNI Demo，以及读卡器/PSAM驱动。"],
        ["普通Linux glibc版本", "不能直接放进Android", "需部署单独Linux中转机，并提供REST接口、安装包、驱动和部署说明。"],
        ["只提供Linux .so，未说明ABI和运行库", "暂不可接受", "必须明确CPU架构、glibc/musl/Bionic、系统版本和硬件驱动。"],
    ], [2100, 1900, 4306], font_size=8.9)
    base.add_callout(doc, "重要说明", "Android虽然基于Linux内核，但Android使用Bionic运行库。普通Linux的glibc .so通常不能直接在Android加载，所以“有Linux SDK”不等于“有Android SDK”。")

    base.add_heading(doc, "3. 需要覆盖的业务能力", 1)
    base.add_table(doc, ["能力", "必须达到的结果"], [
        ["设备连接", "能打开和关闭读卡器，能识别PSAM、授权和设备异常。"],
        ["读卡", "能读取人员账号、卡状态、卡类型、主/补助余额和opCount。"],
        ["扣款", "能按整数分扣款，并返回PSAM编号、PSAM流水和TAC。"],
        ["写后读取", "扣款后能取得新余额和新的opCount。"],
        ["中心上传", "能把同一笔扣款记录上传到一卡通中心并取得成功结果。"],
        ["人员查询", "能按一卡通账号查询人员，并支持必要的人员、部门和黑名单同步。"],
    ], [2000, 6306], font_size=9.1)

    base.add_heading(doc, "4. 最小验收标准", 1)
    base.add_bullets(doc, [
        "SDK或接口库能在目标系统和CPU架构正常加载。",
        "目标读卡器和PSAM能够正常打开。",
        "授权测试卡能够读取，人员能够查询。",
        "经授权的小额扣款成功，卡片余额和opCount正确变化。",
        "同一笔记录能够上传中心，并在一卡通中心查到流水。",
        "重复提交同一订单时不得发生二次扣款。",
    ], numbered=True)
    base.add_callout(doc, "验收边界", "接口文档齐全或程序能启动，不代表对接完成。只有目标设备实机读卡、小额扣款、中心入账和人员查询全部通过，才算满足需求。", fill=base.LIGHT_BLUE)

    base.add_heading(doc, "5. 请贵方回复", 1)
    base.add_table(doc, ["确认项", "贵方回复"], [
        ["现有Windows老接口资料是否可以完整提供？", "可以 / 不可以；版本：________"],
        ["是否有Android 11 SDK？", "有 / 无；支持ABI：________"],
        ["是否有Linux SDK？", "有 / 无；CPU和运行库：________"],
        ["Linux SDK能否在Android Bionic环境运行？", "可以 / 不可以 / 需要单独Linux中转机"],
        ["支持的读卡器和PSAM型号", "____________________________"],
        ["预计可交付时间", "____________________________"],
        ["接口限制或待确认事项", "____________________________"],
    ], [4300, 4006], font_size=9.2)
    base.add_callout(doc, "最终选择", "优先采用Android 11 SDK；如果只有普通Linux SDK，则采用独立Linux中转器；如果Android和Linux均无正式SDK，则继续采用Windows中转器方案。")

    output.parent.mkdir(parents=True, exist_ok=True)
    doc.save(str(output))


MARKDOWN = r'''# 一卡通接口与 Android/Linux SDK 对接需求说明（精简版）

## 我们的需求

请贵方提供现有一卡通接口的完整资料，并优先提供可在 Android 11 上运行的 SDK；如只有 Linux SDK，请明确它是否兼容 Android，或者是否需要单独部署 Linux 中转设备。

我们不要求把现有 Windows DLL 强行转换成 Android `.so`。我们需要的是厂商正式支持、可维护、能连接读卡器和 PSAM 的接口或 SDK。

## 1. 现有老接口资料

请提供以下现有 Windows 接口资料：

1. `Change.dll`、版本、日期、SHA-256；如有 `Change.lib`、`Change.h`一并提供。
2. 打开/关闭读卡器、寻卡、读卡、扣款、连接中心、上传、人员、部门、黑名单等函数说明。
3. `CustomerInfo`、`UPLOADINFO`、人员和部门结构体的字段、长度、对齐、编码和单位。
4. 接口返回码、卡状态、钱包类型和异常处理说明。
5. 读卡器/PSAM驱动、注册工具、授权/初始化文件、依赖DLL和安装顺序。
6. `Change.set`、WebService、应用ID、终端ID、科目ID和混淆参数说明。
7. 只读、扣款、上传、人员查询Demo及测试资源。

如果不能提供DLL源码，至少提供正式头文件、结构体、调用约定、接口文档、错误码和可运行Demo。

## 2. Android SDK 或 Linux SDK

### 2.1 首选：Android 11 SDK

- 支持Android 11和目标ABI，优先`arm64-v8a`。
- 提供`.aar/.jar`、Android NDK编译的`.so`、JNI或Kotlin/Java说明。
- 提供读卡器和PSAM的Android驱动、权限及USB/串口/HID连接方法。
- 支持初始化、设备状态、寻卡、读卡、扣款、写后余额/opCount、中心上传和人员查询。
- 提供Demo、文档、错误码、授权方式、版本和SHA-256。

### 2.2 备选：Linux SDK

- Android NDK/Bionic版本：可以评估直接集成Android，但必须提供目标ABI、JNI Demo和硬件驱动。
- 普通Linux glibc版本：不能直接放进Android，需要单独部署Linux中转机，并提供REST接口和部署说明。
- 未说明ABI和运行库的Linux `.so` 暂不可接受。

Android虽然基于Linux内核，但使用Bionic运行库。普通Linux的glibc `.so` 通常不能直接在Android加载。

## 3. 必须覆盖的能力

设备连接、读卡、扣款、写后余额和opCount、中心上传、人员查询，以及必要的部门和黑名单同步。

## 4. 最小验收

库能加载、读卡器/PSAM能打开、测试卡能读取、人员能查询、授权小额扣款成功、中心能查到流水、重复订单不发生二次扣款。

## 5. 请贵方回复

- 能否完整提供现有Windows老接口资料及版本？
- 是否有Android 11 SDK，支持哪些ABI？
- 是否有Linux SDK，适用什么CPU和运行库？
- Linux SDK能否在Android Bionic运行，还是需要单独Linux中转机？
- 支持哪些读卡器和PSAM？
- 预计何时可以交付？

最终选择：优先Android 11 SDK；只有普通Linux SDK时使用独立Linux中转器；两者均无正式SDK时继续使用Windows中转器。
'''


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--template", type=Path, required=True)
    parser.add_argument("--docx", type=Path, required=True)
    parser.add_argument("--markdown", type=Path, required=True)
    args = parser.parse_args()
    args.markdown.write_text(MARKDOWN.strip() + "\n", encoding="utf-8")
    build(args.template, args.docx)
    print(args.docx)


if __name__ == "__main__":
    main()
