#!/usr/bin/env python3
"""Create/update the S11 personnel, canteen and certificate Apifox scenario."""

from __future__ import annotations

import copy
import importlib.util
from pathlib import Path


BASE_SCRIPT = Path(
    "/Users/guodongwei/Documents/zhct/zhctprompt/"
    "work_food_safety/2026-09-24-apifox-full-api-automation/"
    "apifox/scripts/sync_school_s00_s06_scenarios.py"
)
SPEC = importlib.util.spec_from_file_location("school_s00_s06_sync", BASE_SCRIPT)
if SPEC is None or SPEC.loader is None:
    raise RuntimeError(f"Cannot load shared Apifox helpers from {BASE_SCRIPT}")
shared = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(shared)


NAME = "S11-人员食堂与证照（双库真实写入）"
PREFIX = "APIFOX_S11"
DESCRIPTION = (
    "学校端 S11 人员、食堂与证照双库真实写入场景：食堂新增/编辑、两类许可、人员新增/编辑、"
    "学校证件新增/编辑和 CSV 回查。中文主体、人员、地址、日期、布尔和图片引用均按真实业务风格。"
    "不绑定设备序列号，不触发真实设备或第三方请求；测试数据保留用于原表取证。"
)


OPERATIONS = [
    {
        "name": "读取食堂基线",
        "method": "GET",
        "path": "/school/canteens?schoolId=1&enabled=all",
        "tests": [("食堂基线：返回数组", "pm.expect(__json.data).to.be.an('array')")],
    },
    {
        "name": "新增康源实验学校营养餐厅",
        "method": "POST",
        "path": "/school/canteens",
        "body": {
            "schoolId": 1,
            "name": "康源实验学校营养餐厅（档案{{test_batch}}）",
            "code": "KYYY{{batch_tail}}",
            "address": "北京市海淀区书院路18号综合楼一层",
            "manager": "食堂负责人王老师",
            "phone": "{{canteen_phone}}",
            "enabled": True,
            "instrument": None,
            "ygSn": None,
        },
        "extract": ("canteen_id", "$.data.id"),
        "tests": [
            ("食堂新增：返回正整数 ID", "pm.expect(Number(__json.data.id)).to.be.greaterThan(0)"),
            ("食堂新增：设备绑定为空", "pm.expect(String(__json.data.instrument || '')).to.equal(''); pm.expect(String(__json.data.ygSn || '')).to.equal('')"),
        ],
    },
    {
        "name": "编辑营养餐厅基础档案",
        "method": "PATCH",
        "path": "/school/canteens?id={{canteen_id}}",
        "body": {
            "name": "康源实验学校营养餐厅（档案{{test_batch}}）",
            "address": "北京市海淀区书院路18号综合楼一层东区",
            "manager": "餐饮平台主管王老师",
            "phone": "{{canteen_phone}}",
            "enabled": True,
        },
        "tests": [("食堂编辑：ok=true", "pm.expect(__json.data.ok).to.equal(true)")],
    },
    {
        "name": "新增食堂营业执照",
        "method": "POST",
        "path": "/school/canteen-licenses",
        "body": {
            "canteenId": "{{canteen_id}}",
            "type": "营业执照",
            "number": "YYZZ{{test_batch}}",
            "authority": "北京市海淀区市场监督管理局",
            "permitItems": "餐饮服务、食品销售",
            "issueAt": "2025-01-15",
            "expireAt": "2030-01-14",
            "imageUrl": "https://example.invalid/canteen/business-license.jpg",
        },
        "extract": ("canteen_biz_license_id", "$.data.id"),
        "tests": [("营业执照新增：返回正整数 ID", "pm.expect(Number(__json.data.id)).to.be.greaterThan(0)")],
    },
    {
        "name": "新增食堂食品经营许可证",
        "method": "POST",
        "path": "/school/canteen-licenses",
        "body": {
            "canteenId": "{{canteen_id}}",
            "type": "食品经营许可证",
            "number": "JY{{test_batch}}",
            "authority": "北京市海淀区市场监督管理局食品经营科",
            "permitItems": "热食类食品制售、自制饮品制售",
            "issueAt": "2025-02-01",
            "expireAt": "2030-01-31",
            "imageUrl": "https://example.invalid/canteen/food-license.jpg",
        },
        "extract": ("canteen_food_license_id", "$.data.id"),
        "tests": [("食品经营许可证新增：返回正整数 ID", "pm.expect(Number(__json.data.id)).to.be.greaterThan(0)")],
    },
    {
        "name": "统一更新食堂详细档案与许可证",
        "method": "PATCH",
        "path": "/school/canteen-detail",
        "body": {
            "canteenId": "{{canteen_id}}",
            "name": "康源实验学校营养餐厅（档案{{test_batch}}）",
            "address": "北京市海淀区书院路18号综合楼一层东区",
            "manager": "餐饮平台主管王老师",
            "phone": "{{canteen_phone}}",
            "areaCovered": 860.5,
            "staffCount": 18,
            "eatPersonCount": 1260,
            "remark": "负责全校师生早餐和午餐供应，执行每日留样制度。",
            "biz": {
                "id": "{{canteen_biz_license_id}}",
                "number": "YYZZ{{test_batch}}",
                "authority": "北京市海淀区市场监督管理局",
                "issueAt": "2025-01-15",
                "expireAt": "2030-01-14",
                "imageUrl": "https://example.invalid/canteen/business-license.jpg",
            },
            "food": {
                "id": "{{canteen_food_license_id}}",
                "number": "JY{{test_batch}}",
                "authority": "北京市海淀区市场监督管理局食品经营科",
                "permitItems": "热食类食品制售、自制饮品制售",
                "issueAt": "2025-02-01",
                "expireAt": "2030-01-31",
                "imageUrl": "https://example.invalid/canteen/food-license.jpg",
            },
        },
        "tests": [("食堂详细档案更新：ok=true", "pm.expect(__json.data.ok).to.equal(true)")],
    },
    {
        "name": "回查食堂详细档案与许可证",
        "method": "GET",
        "path": "/school/canteen-detail?canteenId={{canteen_id}}&schoolId=1",
        "tests": [
            ("食堂详情：中文字段和规模数据正确", "pm.expect(__json.data.canteen.name).to.equal('康源实验学校营养餐厅（档案' + pm.variables.get('test_batch') + '）'); pm.expect(__json.data.canteen.manager).to.equal('餐饮平台主管王老师'); pm.expect(Number(__json.data.canteen.areaCovered || __json.data.canteen.area_covered)).to.equal(860.5); pm.expect(Number(__json.data.canteen.staffCount || __json.data.canteen.staff_count)).to.equal(18); pm.expect(Number(__json.data.canteen.eatPersonCount || __json.data.canteen.eat_person_count)).to.equal(1260)"),
            ("食堂详情：两类许可证号正确", "pm.expect(__json.data.licenses.biz.number).to.equal('YYZZ' + pm.variables.get('test_batch')); pm.expect(__json.data.licenses.food.number).to.equal('JY' + pm.variables.get('test_batch'))"),
        ],
    },
    {
        "name": "回查食堂证照汇总",
        "method": "GET",
        "path": "/school/canteens/summary?schoolId=1",
        "tests": [
            ("食堂汇总：包含本轮食堂和两类许可证", "const id=Number(pm.variables.get('canteen_id')); const row=__json.data.find(function(x){return Number(x.canteenId)===id;}); pm.expect(row).to.exist; pm.expect(row.bizLicenseNo).to.equal('YYZZ' + pm.variables.get('test_batch')); pm.expect(row.foodPermitNo).to.equal('JY' + pm.variables.get('test_batch')); pm.expect(row.status).to.equal('有效')"),
        ],
    },
    {
        "name": "新增餐厅营养配餐员陈晓梅",
        "method": "POST",
        "path": "/school/personnel",
        "body": {
            "schoolId": 1,
            "canteenId": "{{canteen_id}}",
            "name": "陈晓梅",
            "gender": "女",
            "phone": "{{person_phone}}",
            "jobTitle": "营养配餐员",
            "healthCertNo": "JKZ{{test_batch}}",
            "healthCertAuthority": "北京市海淀区疾病预防控制中心",
            "healthCertIssueAt": "2025-06-01",
            "healthCertExpireAt": "2028-05-31",
            "healthCertFrontUrl": "https://example.invalid/personnel/health-cert-front.jpg",
            "healthCertBackUrl": "https://example.invalid/personnel/health-cert-back.jpg",
            "idCardNumber": "110108199005128246",
            "accessCard": "CARD{{batch_tail}}",
            "idCardFrontUrl": "https://example.invalid/personnel/id-card-front.jpg",
            "facePhotoUrl": "https://example.invalid/personnel/face-photo.jpg",
            "enabled": True,
        },
        "extract": ("personnel_id", "$.data.id"),
        "tests": [("人员新增：返回正整数 ID", "pm.expect(Number(__json.data.id)).to.be.greaterThan(0)")],
    },
    {
        "name": "回查陈晓梅人员详情",
        "method": "GET",
        "path": "/school/personnel/detail?id={{personnel_id}}",
        "tests": [
            ("人员详情：中文、手机号和健康证正确", "pm.expect(__json.data.name).to.equal('陈晓梅'); pm.expect(__json.data.gender).to.equal('女'); pm.expect(__json.data.phone).to.equal(pm.variables.get('person_phone')); pm.expect(__json.data.jobTitle || __json.data.job_title).to.equal('营养配餐员'); pm.expect(__json.data.healthCertNo || __json.data.health_cert_no).to.equal('JKZ' + pm.variables.get('test_batch'))"),
            ("人员详情：证件图片和布尔状态已保存", "pm.expect(String(__json.data.facePhotoUrl || __json.data.face_photo_url)).to.include('face-photo.jpg'); pm.expect(Number(__json.data.enabled)).to.equal(1)"),
        ],
    },
    {
        "name": "编辑人员岗位并停用",
        "method": "PATCH",
        "path": "/school/personnel?id={{personnel_id}}",
        "body": {
            "schoolId": 1,
            "jobTitle": "营养配餐主管",
            "phone": "{{person_phone}}",
            "enabled": False,
            "entryDate": "2024-09-01",
            "age": 36,
        },
        "tests": [("人员编辑：ok=true", "pm.expect(__json.data.ok).to.equal(true)")],
    },
    {
        "name": "按姓名回查人员列表",
        "method": "GET",
        "path": "/school/personnel?schoolId=1&canteenId={{canteen_id}}&name=陈晓梅&page=1&pageSize=20",
        "tests": [
            ("人员列表：本轮记录岗位和停用状态正确", "const id=Number(pm.variables.get('personnel_id')); const row=__json.data.items.find(function(x){return Number(x.id)===id;}); pm.expect(row).to.exist; pm.expect(row.jobTitle || row.job_title).to.equal('营养配餐主管'); pm.expect(Number(row.enabled)).to.equal(0); pm.expect(Number(row.age)).to.equal(36)"),
        ],
    },
    {
        "name": "新增学校食品安全管理证",
        "method": "POST",
        "path": "/school/certificates",
        "body": {
            "schoolId": 1,
            "owner": "康源实验学校总务处（档案{{test_batch}}）",
            "type": "食品安全管理证",
            "number": "SPAQ{{test_batch}}",
            "expireAt": "2029-08-31",
        },
        "extract": ("school_certificate_id", "$.data.id"),
        "tests": [("学校证件新增：返回正整数 ID", "pm.expect(Number(__json.data.id)).to.be.greaterThan(0)")],
    },
    {
        "name": "编辑学校证件有效期",
        "method": "PATCH",
        "path": "/school/certificates?id={{school_certificate_id}}",
        "body": {
            "owner": "康源实验学校总务处（档案{{test_batch}}）",
            "type": "食品安全管理证",
            "number": "SPAQ{{test_batch}}",
            "expireAt": "2030-08-31",
        },
        "tests": [("学校证件编辑：ID 和新有效期返回正确", "pm.expect(Number(__json.data.id)).to.equal(Number(pm.variables.get('school_certificate_id'))); pm.expect(String(__json.data.expireAt || __json.data.expire_at)).to.include('2030-08-31')")],
    },
    {
        "name": "回查学校证件列表",
        "method": "GET",
        "path": "/school/certificates?schoolId=1&owner=康源实验学校总务处（档案{{test_batch}}）",
        "tests": [
            ("学校证件列表：编号和有效期正确", "const id=Number(pm.variables.get('school_certificate_id')); const row=__json.data.find(function(x){return Number(x.id)===id;}); pm.expect(row).to.exist; pm.expect(row.number).to.equal('SPAQ' + pm.variables.get('test_batch')); pm.expect(String(row.expireAt || row.expire_at)).to.include('2030-08-31'); pm.expect(row.status).to.equal('有效')"),
        ],
    },
    {
        "name": "导出学校证件 CSV",
        "method": "GET",
        "path": "/school/certificates/export.csv?schoolId=1&owner=康源实验学校总务处（档案{{test_batch}}）",
        "tests": [
            ("学校证件 CSV：包含真实主体、证件号和有效期", "pm.expect(__json.data.csv).to.include('康源实验学校总务处（档案' + pm.variables.get('test_batch') + '）'); pm.expect(__json.data.csv).to.include('SPAQ' + pm.variables.get('test_batch')); pm.expect(__json.data.csv).to.include('2030-08-31')"),
        ],
    },
]


def main() -> None:
    api = shared.Apifox()
    by_name = {item["name"]: item for item in api.scenarios()}
    source = by_name["S00-环境与认证（双库）"]
    source_data = api.scenario(int(source["id"]))
    loop_template = source_data["steps"][0]
    login_template = loop_template["children"][0]
    request_template = loop_template["children"][1]

    current = by_name.get(NAME)
    scenario_id = int(current["id"]) if current else api.duplicate(int(source["id"]))
    scenario = api.scenario(scenario_id)
    scenario.update({"name": NAME, "description": DESCRIPTION, "folderId": shared.FOLDER_ID, "ordering": 120})
    loop = copy.deepcopy(loop_template)
    loop["id"] = shared.new_id()
    loop["number"] = 1
    login = shared.make_login(login_template, PREFIX)
    login_pre = login["customHttpRequest"]["preProcessors"][0]["data"]
    login["customHttpRequest"]["preProcessors"][0]["data"] = (
        login_pre
        + "const __stamp = '20260926' + String(Date.now()).slice(-6);\n"
        + "const __tail = String(Date.now()).slice(-8);\n"
        + "pm.variables.set('test_batch', __stamp);\n"
        + "pm.variables.set('batch_tail', __tail.slice(-6));\n"
        + "pm.variables.set('canteen_phone', '136' + __tail);\n"
        + "pm.variables.set('person_phone', '135' + __tail);\n"
    )
    loop["children"] = [login]
    for number, operation in enumerate(OPERATIONS, start=2):
        step = shared.make_request(request_template, **operation)
        step["number"] = number
        loop["children"].append(step)
    scenario["steps"] = [loop]
    api.save(scenario)

    saved = api.scenario(scenario_id)
    requests = shared.flatten_requests(saved["steps"])
    business = [request for request in requests if request.get("path") != "{{base_url}}/auth/login"]
    if len(business) != len(OPERATIONS):
        raise RuntimeError(f"{NAME}: expected {len(OPERATIONS)} business requests, got {len(business)}")
    if not all(shared.request_has_auditable_evidence(request) for request in requests):
        raise RuntimeError(f"{NAME}: one or more requests lack auditable evidence")

    suite = api.test_suite()
    existing = [item for item in suite.get("items", []) if item.get("name") != NAME]
    existing.append({
        "id": shared.new_id(), "name": NAME, "type": "STATIC_TEST_SCENARIO",
        "testScenarios": [{"id": scenario_id, "options": {}}], "options": {},
    })
    suite["items"] = existing
    suite["description"] = (
        "学校端 S00-S11 双库兼容一键串行入口。MySQL 仅允许 foodsafe_test，达梦仅允许 WWWWEB。"
        "写接口必须接口回查并与数据库原表证据合并；删除、设备回调和 SSE 默认关闭。"
    )
    suite.setdefault("options", {})["runMode"] = "serial"
    api.save_test_suite(suite)
    saved_suite = api.test_suite()
    linked = [item["testScenarios"][0]["id"] for item in saved_suite["items"]]
    if scenario_id not in linked:
        raise RuntimeError("S11 was not linked into the one-click test suite")
    print(f"{NAME}: id={scenario_id}, operations={len(business)}, totalRequests={len(requests)}")
    print(f"一键测试-安全入口: scenarios={len(linked)}, suiteId={shared.TEST_SUITE_ID}")


if __name__ == "__main__":
    main()
