from __future__ import annotations

from copy import copy
from datetime import datetime
from pathlib import Path

from openpyxl import load_workbook


CASE_XLSX = Path("测试用例/SaaS_E2E测试用例_单Sheet用例测试列表.xlsx")
FLOW_XLSX = Path("测试用例/订单状态流转_链路流程线整理.xlsx")

CASE_ID = "S-FLOW-078"

CASE_ROW = {
    "用例编号": CASE_ID,
    "用例层级": "订单状态流转用例",
    "所属模块": "下游发起撤销",
    "用例标题": "丸友集订单列表代练中子单-撤销子单并进入撤销完成",
    "登录平台/角色账号": "丸友集：工作室主账号或客服账号；打手：打手子账号。",
    "前置条件": "丸友集管理后台-打手应用-订单列表存在子单状态为代练中的订单；打开订单详情后，子单列表中该代练中子单操作列展示【撤销】入口；订单仍需继续履约。",
    "测试数据": "主单号、来源单号、订单标题、丸友集父单号、目标打手子单号、打手账号、结算金额、撤销原因。",
    "执行步骤": (
        "1. 登录丸友集工作室主账号或客服账号。\n"
        "2. 进入丸友集管理后台-打手应用-订单列表。\n"
        "3. 按主单号、来源单号或订单标题搜索目标订单。\n"
        "4. 打开订单详情，在【订单详情】页签的子单列表中定位状态为代练中的目标子单。\n"
        "5. 点击目标子单操作列的【撤销】。\n"
        "6. 在【撤销子单】弹框中核对子单号，填写结算金额和撤销原因。\n"
        "7. 点击弹框【确认】提交撤销。\n"
        "8. 回到订单列表重新查询同一订单，打开订单详情回查目标子单状态。\n"
        "9. 检查目标子单终态后，确认页面展示【继续发单】或等价续发入口，后续衔接 S-FLOW-032。"
    ),
    "预期结果": (
        "1. 丸友集账号可对代练中子单发起并确认撤销。\n"
        "2. 撤销提交成功后，目标子单状态变为撤销完成或页面等价终态。\n"
        "3. 目标子单进入撤销完成后，订单详情/子单列表可继续展示继续发单/再次发单入口。\n"
        "4. 原目标子单终态不被后续续发动作覆盖，可作为 S-FLOW-032 的前置数据。"
    ),
    "跨端/状态断言": (
        "同一主单号/来源单号下，撤销前目标子单必须为代练中；确认撤销后目标子单必须为撤销完成且不再处于撤销中/代练中；"
        "继续发单入口只在撤销完成后出现；续发时新旧子单号和状态相互独立。"
    ),
    "可组合/被引用关系": "承接 S-FLOW-026 后的打手代练中状态；作为 FLOW-018 起点，后续接 S-FLOW-032 继续发单。",
    "自动化状态": "待自动化",
    "备注": "2026-06-30 新增：覆盖丸友集账号在打手应用-订单列表的订单详情内，对子单状态为代练中的子单直接撤销，撤销完成后继续发单。",
}

FLOW_018_SUMMARY = {
    "链路编号": "FLOW-018",
    "链路名称": "丸友集订单列表代练中子单撤销-撤销完成后续发",
    "链路类型": "丸友集主动撤销后多子单续发",
    "起点状态": "丸友集打手应用-订单列表目标子单为代练中",
    "终点状态": "原子单撤销完成；下一子单待接单/已发单/代练中",
    "用例编号序列": "S-FLOW-078 -> S-FLOW-032",
    "用例链路（编号+标题）": (
        "S-FLOW-078(丸友集订单列表代练中子单-撤销子单并进入撤销完成) -> "
        "S-FLOW-032(前一子单已撤销/已取消状态-续发下一子单)"
    ),
    "涉及模块": "下游发起撤销 -> 多子单履约",
    "适用场景": "验证丸友集账号在打手应用-订单列表的订单详情内，对子单状态为代练中的子单直接撤销，撤销完成后继续发单。",
    "数据复用建议": "可复用 S-FLOW-026 形成的打手代练中订单；撤销完成后立即作为 S-FLOW-032 的前置数据。",
    "注意事项/缺口": "替换原 FLOW-018 中 S-FLOW-030 打手申请撤销链路；本链路不依赖打手先发起撤销，重点校验【撤销子单】弹框的结算金额、撤销原因和确认提交。",
}


def headers(ws) -> dict[str, int]:
    return {str(cell.value).strip(): cell.column for cell in ws[1] if cell.value}


def find_row(ws, key: str, column: int = 1) -> int | None:
    for row in range(2, ws.max_row + 1):
        if str(ws.cell(row, column).value or "").strip() == key:
            return row
    return None


def copy_row_style(ws, source_row: int, target_row: int) -> None:
    for col in range(1, ws.max_column + 1):
        src = ws.cell(source_row, col)
        dst = ws.cell(target_row, col)
        if src.has_style:
            dst._style = copy(src._style)
        if src.number_format:
            dst.number_format = src.number_format
        if src.alignment:
            dst.alignment = copy(src.alignment)
        if src.font:
            dst.font = copy(src.font)
        if src.fill:
            dst.fill = copy(src.fill)
        if src.border:
            dst.border = copy(src.border)


def upsert_case_row(ws, row_values: dict[str, str]) -> int:
    h = headers(ws)
    row = find_row(ws, CASE_ID)
    if row is None:
        row = ws.max_row + 1
        copy_row_style(ws, row - 1, row)
    for name, value in row_values.items():
        col = h.get(name)
        if col:
            ws.cell(row, col).value = value
    return row


def update_single_sheet_workbook() -> None:
    wb = load_workbook(CASE_XLSX)
    for sheet_name in ["订单状态流转", "用例测试列表"]:
        if sheet_name in wb.sheetnames:
            upsert_case_row(wb[sheet_name], CASE_ROW)
    wb.save(CASE_XLSX)


def update_flow_summary(ws) -> None:
    h = headers(ws)
    row = find_row(ws, "FLOW-018")
    if row is None:
        row = ws.max_row + 1
        copy_row_style(ws, row - 1, row)
    for name, value in FLOW_018_SUMMARY.items():
        col = h.get(name)
        if col:
            ws.cell(row, col).value = value


def update_raw_index(ws) -> None:
    row_values = {
        "用例编号": CASE_ROW["用例编号"],
        "所属模块": CASE_ROW["所属模块"],
        "用例标题": CASE_ROW["用例标题"],
        "前置条件": CASE_ROW["前置条件"],
        "预期结果": CASE_ROW["预期结果"],
        "执行步骤": CASE_ROW["执行步骤"],
    }
    upsert_case_row(ws, row_values)


def delete_flow_detail_rows(ws, flow_id: str) -> int:
    start = find_row(ws, flow_id)
    if start is None:
        return ws.max_row + 1
    row = start
    while row <= ws.max_row and str(ws.cell(row, 1).value or "").strip() == flow_id:
        ws.delete_rows(row, 1)
    return start


def update_flow_details(ws) -> None:
    start = delete_flow_detail_rows(ws, "FLOW-018")
    rows = [
        [
            "FLOW-018",
            1,
            CASE_ID,
            CASE_ROW["所属模块"],
            CASE_ROW["用例标题"],
            CASE_ROW["前置条件"],
            CASE_ROW["预期结果"],
        ],
        [
            "FLOW-018",
            2,
            "S-FLOW-032",
            "多子单履约",
            "前一子单已撤销/已取消状态-续发下一子单",
            "已执行 S-FLOW-078，丸友集订单详情目标子单状态已变为撤销完成，页面展示继续发单或等价续发入口。",
            "1. 第一子单保持撤销完成。\n2. 第二子单进入待接单、已发单或代练中。\n3. 续发结果在丸友集侧可见，新旧子单状态、子单号和发单记录相互独立。",
        ],
    ]
    ws.insert_rows(start, len(rows))
    copy_row_style(ws, start + len(rows), start)
    copy_row_style(ws, start + len(rows), start + 1)
    for offset, row_values in enumerate(rows):
        for col, value in enumerate(row_values, start=1):
            ws.cell(start + offset, col).value = value


def update_coverage(ws) -> None:
    h = headers(ws)

    updates = {
        "S-FLOW-030": {
            "覆盖次数": 1,
            "出现链路": "FLOW-017",
            "是否已覆盖": "是",
            "备注": "FLOW-018 已改为丸友集订单详情内主动撤销子单；S-FLOW-030 仅保留打手申请撤销后丸友集同意撤销链路。",
        },
        "S-FLOW-032": {
            "覆盖次数": 3,
            "出现链路": "FLOW-018、FLOW-022、FLOW-046",
            "是否已覆盖": "是",
            "备注": "承接 S-FLOW-078 撤销完成、S-FLOW-039 取消完成、S-FLOW-077 已取消等终态后的丸友集侧续发。",
        },
    }
    for case_id, row_update in updates.items():
        row = find_row(ws, case_id)
        if not row:
            continue
        for name, value in row_update.items():
            col = h.get(name)
            if col:
                ws.cell(row, col).value = value

    row = find_row(ws, CASE_ID)
    if row is None:
        row = ws.max_row + 1
        copy_row_style(ws, row - 1, row)
    values = {
        "用例编号": CASE_ID,
        "所属模块": CASE_ROW["所属模块"],
        "用例标题": CASE_ROW["用例标题"],
        "覆盖次数": 1,
        "出现链路": "FLOW-018",
        "是否已覆盖": "是",
        "备注": "新增覆盖丸友集订单详情代练中子单撤销，撤销完成后接 S-FLOW-032 继续发单。",
    }
    for name, value in values.items():
        col = h.get(name)
        if col:
            ws.cell(row, col).value = value


def update_flow_workbook() -> None:
    wb = load_workbook(FLOW_XLSX)
    update_flow_summary(wb["链路流程线"])
    update_flow_details(wb["链路步骤明细"])
    update_coverage(wb["用例覆盖索引"])
    update_raw_index(wb["原始用例索引"])
    wb["说明"].append(["更新记录", f"{datetime.now():%Y-%m-%d %H:%M:%S} 新增 {CASE_ID}，FLOW-018 改为丸友集订单详情代练中子单撤销后续发。"])
    wb.save(FLOW_XLSX)


def main() -> None:
    update_single_sheet_workbook()
    update_flow_workbook()
    print(f"synced {CASE_ID} and FLOW-018")


if __name__ == "__main__":
    main()
