from __future__ import annotations

import copy
import json
from pathlib import Path

import openpyxl
from openpyxl.styles import PatternFill


ROOT = Path(__file__).resolve().parents[1]
CASE_XLSX = ROOT / "SaaS_E2E测试用例_单Sheet用例测试列表.xlsx"
FLOW_XLSX = ROOT / "订单状态流转_链路流程线整理.xlsx"
JSON_FILES = [
    ROOT / "scripts" / "order_status_flow_cases.json",
    ROOT / "runtime" / "order_status_flow_cases_for_sheet.json",
    ROOT / "runtime" / "order_status_flow_cases_for_excel.json",
]

CASE_ID = "S-FLOW-068"


CASE_016_UPDATES = {
    "用例标题": "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销-丸掌柜同意撤销",
    "预期结果": (
        "1. 丸掌柜子单列表中目标子单的订单状态变为撤销结束。\n"
        "2. 丸友集父单或订单进入已撤销、已取消或撤销完成状态。\n"
        "3. 丸友集订单不可继续发给打手。\n"
        "4. 打手侧查询不到此单。"
    ),
    "跨端/状态断言": (
        "1. 同意撤销后当前子单终结，子单列表状态为撤销结束，主单如需继续履约，应走撤销结束后继续发子单流程。\n"
        "2. 撤销处理备注和处理结果两端一致。\n"
        "3. S-FLOW-016 原丸掌柜无法同意撤销的问题已修复，FLOW-008 后续衔接 S-FLOW-068。"
    ),
    "自动化状态": "已自动化",
    "备注": "2026-06-24按修复后实测更新：丸掌柜可同意撤销，子单列表状态变为撤销结束，后续可继续发单。",
}

CASE_068 = {
    "用例编号": CASE_ID,
    "用例层级": "订单状态流转用例",
    "所属模块": "上游发单",
    "用例标题": "【丸掌柜】主单待接单状态/子单撤销结束状态-继续发子单",
    "登录平台/角色账号": "丸掌柜：企业主账号或客服账号；丸友集：工作室主账号或客服账号；打手：打手子账号。",
    "前置条件": "丸友集已接单未发打手阶段申请撤销，丸掌柜已同意撤销；丸掌柜主单下已有目标子单订单状态为撤销结束，主单仍需继续履约。",
    "测试数据": "来源单号、订单标题、丸掌柜主单号、丸掌柜子单号、丸友集父单号、打手子单号、操作原因、操作凭证、金额信息。",
    "执行步骤": (
        "1. 登录丸掌柜账号。\n"
        "2. 进入【丸掌柜】商家管理-订单管理。\n"
        "3. 按来源单号或订单标题查询目标主单。\n"
        "4. 点击主单号进入订单详情。\n"
        "5. 确认原子单列表中的订单状态为撤销结束。\n"
        "6. 点击继续发子单或页面展示的继续发单入口。\n"
        "7. 填写新子单信息并选择丸友集推单策略。\n"
        "8. 提交并推送新子单。\n"
        "9. 在丸掌柜订单管理页面，按来源单号或订单标题查询目标订单。\n"
        "10. 点击主单号进入订单详情。\n"
        "11. 记录丸掌柜主单订单状态。\n"
        "12. 记录丸掌柜子单状态。\n"
        "13. 登录丸友集账号，进入工作室履约应用-抢单大厅。\n"
        "14. 按来源单号或订单标题查询目标订单。\n"
        "15. 如查询到订单，点击订单详情并记录丸友集父单状态和打手子单状态。\n"
        "16. 如查询不到订单，记录查询条件、当前页签和空结果。"
    ),
    "预期结果": (
        "1. 原子单订单状态保持撤销结束。\n"
        "2. 新子单创建成功，状态为待接单或待接单-已推单。\n"
        "3. 丸友集抢单大厅可查询到新子单对应的订单。\n"
        "4. 主单仍按整体履约继续流转。"
    ),
    "跨端/状态断言": (
        "1. 继续发子单不能覆盖原撤销结束子单。\n"
        "2. 新旧子单状态、子单号和推单记录相互独立。\n"
        "3. FLOW-008 中 S-FLOW-016 后应衔接本用例，不复用取消订单状态的 S-FLOW-012。"
    ),
    "可组合/被引用关系": "FLOW-008：S-FLOW-016 后续撤销结束状态继续发子单。",
    "自动化状态": "已自动化",
    "备注": "2026-06-24新增：用于丸友集已接单未发打手阶段，丸掌柜同意撤销后子单状态为撤销结束的继续发单场景。",
}


def header_map(sheet) -> dict[str, int]:
    return {str(sheet.cell(1, column).value): column for column in range(1, sheet.max_column + 1)}


def row_by_id(sheet, id_column: int, item_id: str) -> int | None:
    for row in range(2, sheet.max_row + 1):
        if sheet.cell(row, id_column).value == item_id:
            return row
    return None


def copy_row_style(sheet, source_row: int, target_row: int) -> None:
    for column in range(1, sheet.max_column + 1):
        source = sheet.cell(source_row, column)
        target = sheet.cell(target_row, column)
        if source.has_style:
            target._style = copy.copy(source._style)
        target.number_format = source.number_format
        target.protection = copy.copy(source.protection)
        target.alignment = copy.copy(source.alignment)
        target.fill = PatternFill(fill_type=None)
    sheet.row_dimensions[target_row].height = sheet.row_dimensions[source_row].height


def upsert_case_sheet() -> None:
    workbook = openpyxl.load_workbook(CASE_XLSX)
    sheet = workbook["订单状态流转"]
    headers = header_map(sheet)

    row_016 = row_by_id(sheet, headers["用例编号"], "S-FLOW-016")
    if row_016:
        for field, value in CASE_016_UPDATES.items():
            if field in headers:
                sheet.cell(row_016, headers[field], value)

    existing_068 = row_by_id(sheet, headers["用例编号"], CASE_ID)
    if existing_068:
        row_068 = existing_068
    else:
        insert_after = row_by_id(sheet, headers["用例编号"], "S-FLOW-016") or sheet.max_row
        row_068 = insert_after + 1
        sheet.insert_rows(row_068)
        copy_row_style(sheet, insert_after, row_068)

    for field, value in CASE_068.items():
        if field in headers:
            sheet.cell(row_068, headers[field], value)

    workbook.save(CASE_XLSX)


def update_case_dict(case: dict) -> None:
    if case.get("用例编号") == "S-FLOW-016":
        case.update(CASE_016_UPDATES)


def upsert_json_cases() -> None:
    for path in JSON_FILES:
        if not path.exists():
            continue
        data = json.loads(path.read_text(encoding="utf-8"))
        found_016 = False
        found_068 = False
        for case in data:
            if case.get("用例编号") == "S-FLOW-016":
                update_case_dict(case)
                found_016 = True
            if case.get("用例编号") == CASE_ID:
                case.update(CASE_068)
                found_068 = True
        if not found_068:
            insert_index = next(
                (index + 1 for index, case in enumerate(data) if case.get("用例编号") == "S-FLOW-016"),
                len(data),
            )
            data.insert(insert_index, dict(CASE_068))
        if not found_016:
            data.append({"用例编号": "S-FLOW-016", **CASE_016_UPDATES})
        path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def case_link(cases: dict[str, dict[str, str]], case_ids: list[str]) -> str:
    return " -> ".join(f"{case_id}({cases[case_id]['用例标题']})" for case_id in case_ids)


def update_flow_workbook() -> None:
    workbook = openpyxl.load_workbook(FLOW_XLSX)

    case_workbook = openpyxl.load_workbook(CASE_XLSX, data_only=False)
    case_sheet = case_workbook["订单状态流转"]
    case_headers = header_map(case_sheet)
    cases = {}
    for row in range(2, case_sheet.max_row + 1):
        case_id = case_sheet.cell(row, case_headers["用例编号"]).value
        if case_id:
            cases[case_id] = {
                header: case_sheet.cell(row, column).value or ""
                for header, column in case_headers.items()
                if header != "None"
            }

    flow_ids = ["S-FLOW-007", "S-FLOW-014", "S-FLOW-015", "S-FLOW-016", "S-FLOW-068"]
    flow_sheet = workbook["链路流程线"]
    flow_headers = header_map(flow_sheet)
    flow_row = row_by_id(flow_sheet, flow_headers["链路编号"], "FLOW-008")
    if flow_row:
        flow_sheet.cell(flow_row, flow_headers["链路类型"], "丸友集撤销正向")
        flow_sheet.cell(flow_row, flow_headers["终点状态"], "旧子单撤销结束；新子单待接单/已推单")
        flow_sheet.cell(flow_row, flow_headers["用例编号序列"], " -> ".join(flow_ids))
        flow_sheet.cell(flow_row, flow_headers["用例链路（编号+标题）"], case_link(cases, flow_ids))
        flow_sheet.cell(
            flow_row,
            flow_headers["注意事项/缺口"],
            "S-FLOW-016 修复后同意撤销落点为撤销结束；FLOW-008 后续衔接 S-FLOW-068，不复用取消订单状态的 S-FLOW-012。",
        )

    detail = workbook["链路步骤明细"]
    detail_headers = header_map(detail)
    flow008_rows = [
        row for row in range(2, detail.max_row + 1)
        if detail.cell(row, detail_headers["链路编号"]).value == "FLOW-008"
    ]
    if flow008_rows:
        start = min(flow008_rows)
        count = len(flow008_rows)
        detail.delete_rows(start, count)
        for offset, case_id in enumerate(flow_ids):
            row = start + offset
            detail.insert_rows(row)
            style_source = max(2, row - 1)
            copy_row_style(detail, style_source, row)
            case = cases[case_id]
            values = {
                "链路编号": "FLOW-008",
                "步骤序号": offset + 1,
                "用例编号": case_id,
                "所属模块": case.get("所属模块", ""),
                "用例标题": case.get("用例标题", ""),
                "前置条件": case.get("前置条件", ""),
                "预期结果": case.get("预期结果", ""),
            }
            for field, value in values.items():
                detail.cell(row, detail_headers[field], value)

    raw = workbook["原始用例索引"]
    raw_headers = header_map(raw)
    for case_id in ["S-FLOW-016", CASE_ID]:
        row = row_by_id(raw, raw_headers["用例编号"], case_id)
        if not row:
            insert_after = row_by_id(raw, raw_headers["用例编号"], "S-FLOW-016") or raw.max_row
            row = insert_after + 1
            raw.insert_rows(row)
            copy_row_style(raw, insert_after, row)
        case = cases[case_id]
        for field in ["用例编号", "所属模块", "用例标题", "前置条件", "预期结果", "执行步骤"]:
            if field in raw_headers:
                raw.cell(row, raw_headers[field], case.get(field, ""))

    coverage = workbook["用例覆盖索引"]
    coverage_headers = header_map(coverage)
    coverage_map = {
        "S-FLOW-012": ("1", "FLOW-007", "是", ""),
        "S-FLOW-016": ("1", "FLOW-008", "是", ""),
        CASE_ID: ("1", "FLOW-008", "是", ""),
    }
    for case_id, (count, flows, covered, note) in coverage_map.items():
        row = row_by_id(coverage, coverage_headers["用例编号"], case_id)
        if not row:
            insert_after = row_by_id(coverage, coverage_headers["用例编号"], "S-FLOW-016") or coverage.max_row
            row = insert_after + 1
            coverage.insert_rows(row)
            copy_row_style(coverage, insert_after, row)
        case = cases.get(case_id, {})
        values = {
            "用例编号": case_id,
            "所属模块": case.get("所属模块", ""),
            "用例标题": case.get("用例标题", ""),
            "覆盖次数": int(count),
            "出现链路": flows,
            "是否已覆盖": covered,
            "备注": note,
        }
        for field, value in values.items():
            if field in coverage_headers:
                coverage.cell(row, coverage_headers[field], value)

    workbook.save(FLOW_XLSX)


def main() -> None:
    upsert_case_sheet()
    upsert_json_cases()
    update_flow_workbook()
    print("FLOW-008 revoke-end case synced")


if __name__ == "__main__":
    main()
