from __future__ import annotations

import json
import sys
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_JSON = Path("scripts/order_status_flow_cases.json")
LEDGER_JSON = Path("runtime/e2e_accounts.json")
TARGET_MAIN_ORDER_NO = "BO20260623112007360151"
TARGET_SOURCE_ORDER_NO = "E2EORDER0623111929"


CASE_UPDATES = {
    "S-FLOW-012": {
        "可组合/被引用关系": "承接丸掌柜侧子单撤销/取消后的继续发单；FLOW-046 的拒绝撤销分支不再复用本用例。",
        "备注": "2026-06-30 修正：FLOW-046 改由丸友集侧 S-FLOW-032 续发。",
        "自动化状态": "已自动化",
    },
    "S-FLOW-077": {
        "用例标题": "【丸掌柜】拒绝丸友集撤销申请-按发单/代练阶段回写子单状态",
        "预期结果": (
            "1. 丸掌柜拒绝撤销成功。\n"
            "2. 打手未接单分支：丸掌柜侧子单为异常中，丸友集侧子单为已取消，可衔接 S-FLOW-032。\n"
            "3. 打手代练中分支：丸友集侧目标子单为已完成，可衔接 S-FLOW-072。"
        ),
        "跨端/状态断言": (
            "丸掌柜拒绝处理结果、丸友集子单状态、主单号/来源单号/子单号一致；"
            "未接单分支不进入处罚追缴，代练中分支可进入处罚追缴。"
        ),
        "可组合/被引用关系": "承接 S-FLOW-075 或 S-FLOW-033；未接单撤销拒绝后接 S-FLOW-032，代练中撤销主单拒绝后接 S-FLOW-072。",
        "自动化状态": "已自动化",
        "备注": "2026-06-30 修正：FLOW-046 的非代练中拒绝撤销结果为丸友集已取消，后续由丸友集侧 S-FLOW-032 续发。",
    },
    "S-FLOW-032": {
        "来源/组合依据": "whiteboard_exported_image.png + 订单状态流转链路修正：多子单履约续发",
        "所属模块": "多子单履约",
        "用例标题": "前一子单已撤销/已取消状态-续发下一子单",
        "前置条件": "第一子单已发起撤销或取消并审批通过，状态进入已取消、已撤销或页面展示的终态。",
        "执行步骤": (
            "1. 登录丸友集主账号，进入丸友集-工作室履约应用-订单列表。\n"
            "2. 搜索目标订单。\n"
            "3. 在订单列表行点击【操作】。\n"
            "4. 在主单/子单列表弹窗中确认前一子单状态为已取消、已撤销或页面展示的终态。\n"
            "5. 点击弹窗右下角【继续发单】。\n"
            "6. 在【请添加子单】区域确认/补充订单内容、分配方式、发单价、联系电话等子单信息。\n"
            "7. 点击【确认发单】。\n"
            "8. 在提示“订单将由新打手接单，请及时处理上一笔打手订单”弹窗中点击【确认】。\n"
            "9. 留在丸友集订单列表回查新子单已发到打手抢单大厅；后续由丸友集下的打手账号查看/抢单。"
        ),
        "预期结果": (
            "1. 第一子单保持已取消、已撤销或页面终态。\n"
            "2. 第二子单进入待接单、已发单或代练中。\n"
            "3. 续发结果在丸友集侧可见，订单已进入打手抢单大厅，后续只需切换丸友集下的打手账号查看或抢单。"
        ),
        "跨端/状态断言": "已终态子单不能被覆盖；续发后新旧子单状态、子单号和发单记录相互独立；本用例不切换丸掌柜回查。",
        "可组合/被引用关系": "承接 S-FLOW-030、S-FLOW-039、S-FLOW-077 等子单撤销/取消终态；被 FLOW-018、FLOW-022、FLOW-046 引用。",
        "自动化状态": "已自动化",
        "备注": "2026-06-30 修正：承接 FLOW-046 中 S-FLOW-077 后丸友集侧已取消子单的续发。",
    },
}


FLOW_046_SEQUENCE = ["S-FLOW-007", "S-FLOW-014", "S-FLOW-021", "S-FLOW-075", "S-FLOW-077", "S-FLOW-032"]
FLOW_046_SUMMARY = [
    "FLOW-046",
    "已发打手待接单-丸友集申请撤销主单-丸掌柜拒绝撤销-丸友集续发下一子单",
    "打手未接单撤销拒绝后丸友集续发",
    "已发打手；打手未接单；丸友集已申请撤销；丸掌柜拒绝撤销后丸友集侧子单已取消",
    "撤销被拒绝；丸友集从已取消子单继续发单，下一子单进入待接单/已发单",
    "S-FLOW-007 -> S-FLOW-014 -> S-FLOW-021 -> S-FLOW-075 -> S-FLOW-077 -> S-FLOW-032",
    (
        "S-FLOW-007(创建主单已推单) -> S-FLOW-014(丸友集确认接单) -> "
        "S-FLOW-021(丸友集立即发单到打手) -> S-FLOW-075(丸友集申请撤销此单) -> "
        "S-FLOW-077(丸掌柜拒绝撤销，丸友集子单已取消) -> S-FLOW-032(丸友集侧续发下一子单)"
    ),
    "上游发单 -> 丸友集申请撤销 -> 丸掌柜拒绝撤销 -> 丸友集续发下一子单",
    "验证打手未接单阶段丸掌柜拒绝撤销后，不进入处罚追缴，由丸友集侧基于已取消子单续发下一子单。",
    "S-FLOW-032 在本链路中作为拒绝撤销后的丸友集侧续发动作。",
    "2026-06-30 修正：FLOW-046 由 S-FLOW-077 后接 S-FLOW-032，不再接 S-FLOW-012。",
]


def header_map(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 update_case_sheet(path: Path) -> dict[str, dict[str, str]]:
    wb = load_workbook(path)
    ws = wb["订单状态流转"]
    headers = header_map(ws)
    rows: dict[str, dict[str, str]] = {}
    for case_id, updates in CASE_UPDATES.items():
        row = find_row(ws, case_id)
        if not row:
            continue
        for column_name, value in updates.items():
            column = headers.get(column_name)
            if column:
                ws.cell(row, column).value = value
        rows[case_id] = {
            "module": str(ws.cell(row, headers["所属模块"]).value or ""),
            "title": str(ws.cell(row, headers["用例标题"]).value or ""),
            "precondition": str(ws.cell(row, headers["前置条件"]).value or ""),
            "expected": str(ws.cell(row, headers["预期结果"]).value or ""),
        }
    wb.save(path)
    return rows


def update_flow_workbook(path: Path, case_rows: dict[str, dict[str, str]]) -> None:
    wb = load_workbook(path)

    summary = wb["链路流程线"]
    row = find_row(summary, "FLOW-046")
    if row:
        for column, value in enumerate(FLOW_046_SUMMARY, start=1):
            summary.cell(row, column).value = value

    raw = wb["原始用例索引"]
    raw_headers = header_map(raw)
    raw_mapping = {
        "用例标题": "title",
        "前置条件": "precondition",
        "预期结果": "expected",
    }
    for case_id, values in case_rows.items():
        row = find_row(raw, case_id)
        if not row:
            continue
        if "所属模块" in raw_headers:
            raw.cell(row, raw_headers["所属模块"]).value = values["module"]
        for column_name, key in raw_mapping.items():
            if column_name in raw_headers:
                raw.cell(row, raw_headers[column_name]).value = values[key]

    details = wb["链路步骤明细"]
    start_row = find_row(details, "FLOW-046") or (details.max_row + 1)
    while start_row <= details.max_row and str(details.cell(start_row, 1).value or "").strip() == "FLOW-046":
        details.delete_rows(start_row, 1)
    details.insert_rows(start_row, len(FLOW_046_SEQUENCE))
    for offset, case_id in enumerate(FLOW_046_SEQUENCE):
        values = case_rows.get(case_id)
        if not values:
            source_row = find_row(raw, case_id)
            values = {
                "module": str(raw.cell(source_row, 2).value or "") if source_row else "",
                "title": str(raw.cell(source_row, 3).value or "") if source_row else "",
                "precondition": str(raw.cell(source_row, 4).value or "") if source_row else "",
                "expected": str(raw.cell(source_row, 5).value or "") if source_row else "",
            }
        for column, value in enumerate(
            [
                "FLOW-046",
                offset + 1,
                case_id,
                values["module"],
                values["title"],
                values["precondition"],
                values["expected"],
            ],
            start=1,
        ):
            details.cell(start_row + offset, column).value = value

    coverage = wb["用例覆盖索引"]
    coverage_updates = {
        "S-FLOW-012": (2, "FLOW-007、FLOW-012", "是", "FLOW-046 改由丸友集侧 S-FLOW-032 续发；本用例仅保留丸掌柜侧子单取消后的继续发单。"),
        "S-FLOW-032": (3, "FLOW-018、FLOW-022、FLOW-046", "是", "承接 FLOW-046 中 S-FLOW-077 后丸友集侧已取消子单的续发。"),
        "S-FLOW-077": (2, "FLOW-046、FLOW-014", "是", "FLOW-046 未接单撤销拒绝后接 S-FLOW-032；FLOW-014 代练中撤销主单拒绝后接 S-FLOW-072。"),
    }
    for case_id, (count, flows, automated, note) in coverage_updates.items():
        row = find_row(coverage, case_id)
        if not row:
            continue
        values = case_rows.get(case_id)
        if values:
            coverage.cell(row, 2).value = values["module"]
            coverage.cell(row, 3).value = values["title"]
        coverage.cell(row, 4).value = count
        coverage.cell(row, 5).value = flows
        coverage.cell(row, 6).value = automated
        coverage.cell(row, 7).value = note

    note_sheet = wb["说明"]
    note_sheet.append(["更新记录", f"{datetime.now():%Y-%m-%d %H:%M:%S} 修正 FLOW-046：S-FLOW-077 后接 S-FLOW-032，由丸友集侧续发下一子单。"])
    wb.save(path)


def update_case_json(path: Path) -> None:
    data = json.loads(path.read_text(encoding="utf-8"))
    for item in data:
        case_id = item.get("用例编号")
        updates = CASE_UPDATES.get(case_id)
        if updates:
            item.update(updates)
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")


def repair_ledger(path: Path) -> None:
    if not path.exists():
        return
    payload = json.loads(path.read_text(encoding="utf-8"))
    for item in payload.get("dispatched_orders", []):
        if item.get("main_order_no") != TARGET_MAIN_ORDER_NO and item.get("source_order_no") != TARGET_SOURCE_ORDER_NO:
            continue
        consumed = [case_id for case_id in item.get("consumed_by_cases", []) if case_id != "S-FLOW-012"]
        for key in [
            "continue_dispatch_after_sub_cancelled_by",
            "continue_dispatch_after_sub_cancelled_before_detail_text",
            "continue_dispatch_after_sub_cancelled_text",
            "continue_dispatch_after_sub_cancelled_detail_status_text",
            "continue_dispatch_after_sub_cancelled_wanyouji_hall_status_texts",
            "wanyouji_hall_status",
        ]:
            item.pop(key, None)
        item.update(
            {
                "status": "revoke_rejected_wait_wanyouji_continue_dispatch",
                "current_flow_state": "wanyouji_cancelled_after_revoke_rejected_wait_continue_dispatch",
                "wanzhanggui_main_status": "异常中",
                "wanzhanggui_sub_order_status": "异常中",
                "wanyouji_sub_order_status": "已取消",
                "wanzhanggui_sub_order_list_status": "revoke_rejected_wait_wanyouji_continue_dispatch",
                "wanyouji_visibility": "order_list_visible_cancelled",
                "available_for_cases": ["S-FLOW-032"],
                "consumed_by_cases": consumed,
                "updated_at": datetime.now().isoformat(timespec="seconds"),
                "flow_046_corrected_next_case": "S-FLOW-032",
            }
        )
    path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")


def main() -> None:
    case_rows = update_case_sheet(CASE_XLSX)
    update_flow_workbook(FLOW_XLSX, case_rows)
    update_case_json(CASE_JSON)
    if "--repair-ledger" in sys.argv:
        repair_ledger(LEDGER_JSON)
    print("FLOW-046 synced to S-FLOW-077 -> S-FLOW-032")


if __name__ == "__main__":
    main()
