from __future__ import annotations

import os
from dataclasses import dataclass
from datetime import datetime

import pytest
from playwright.sync_api import Page

from e2e.pages.wanzhanggui_order_page import ManualOrderData, WanyoujiFulfillmentPage, WanzhangguiOrderPage
from e2e.utils.account_store import account_store


@dataclass(frozen=True)
class AutoAcceptanceCase:
    use_case_no: str
    case_id: str
    title: str
    wanzhanggui_phone: str
    wanyouji_phone: str
    strategy_name: str
    strategy_type: str
    expected_scope: str
    sub_order_title_suffix: str
    verify_mode: str = "hall"
    merchant_name: str = ""


@dataclass(frozen=True)
class GuaranteeAutoAcceptanceCase:
    use_case_no: str
    case_id: str
    title: str
    wanzhanggui_phone: str
    wanyouji_phone: str
    workshop_name: str
    strategy_name: str
    strategy_type: str
    sub_order_title_suffix: str
    receive_price: str = "80"
    dispatch_price: str = "70"
    security_deposit: str = "0"
    efficiency_deposit: str = "0"
    expected_wanzhanggui_statuses: tuple[str, ...] = ("待接单", "代练中")
    verify_mode: str = "create"
    close_guarantee_after_case: bool = False


CASES = [
    # 用例1：关闭测试001自动接指派单执行1.2，再开启测试001自动接指派单执行1.1。
    AutoAcceptanceCase(
        use_case_no="1",
        case_id="AUTO-ACCEPT-PRIVATE",
        title="丸掌柜手工录单创建私单外来订单并发布到丸友集",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        strategy_name="指定-旺仔",
        strategy_type="单平台指定",
        expected_scope="私单",
        sub_order_title_suffix="私单标识",
        verify_mode="branch",
        merchant_name="测试001",
    ),
    # 用例1.2：关闭自动接指派单后创建私单，校验丸掌柜待接单且丸友集抢单大厅-私单可见。
    AutoAcceptanceCase(
        use_case_no="1.2",
        case_id="AUTO-ACCEPT-PRIVATE-HALL",
        title="私单未自动接单时丸友集私单大厅可见性验证",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        strategy_name="指定-旺仔",
        strategy_type="单平台指定",
        expected_scope="私单",
        sub_order_title_suffix="私单标识",
        verify_mode="hall",
        merchant_name="测试001",
    ),
    # 用例1.1：开启自动接指派单后创建私单，校验丸掌柜代练中且丸友集订单列表已接单。
    AutoAcceptanceCase(
        use_case_no="1.1",
        case_id="AUTO-ACCEPT-PRIVATE-ACCEPTED",
        title="私单自动接单后丸友集订单列表状态回查",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        strategy_name="指定-旺仔",
        strategy_type="单平台指定",
        expected_scope="私单",
        sub_order_title_suffix="私单标识",
        verify_mode="accepted",
        merchant_name="测试001",
    ),
    # 用例2：创建公池单，校验丸友集抢单大厅-公池单可见。
    AutoAcceptanceCase(
        use_case_no="2",
        case_id="AUTO-ACCEPT-POOL",
        title="丸掌柜手工录单创建公池单外来订单并发布到丸友集",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        strategy_name="多发测试",
        strategy_type="多工作室同时分发",
        expected_scope="公池单",
        sub_order_title_suffix="公池单标识",
        verify_mode="hall",
    ),
]


GUARANTEE_CASES = [
    # 用例3.1：独立创建一笔担保私单；搜索到丸掌柜状态为代练中后点击详情提取ORB，再校验担保交易扣除金额；结束后不关闭担保。
    GuaranteeAutoAcceptanceCase(
        use_case_no="3.1",
        case_id="AUTO-ACCEPT-GUARANTEE-TRADE-AMOUNT",
        title="担保单代练中后进详情提取ORB并核对担保交易扣除金额",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        workshop_name="旺仔工作室",
        strategy_name="指定-旺仔",
        strategy_type="单平台指定",
        sub_order_title_suffix="担保私单标识",
        verify_mode="trade_amount",
    ),
    # 用例3.2：检查担保已开启，若关闭则开启；独立创建一笔发单价80000的担保私单，结束后不关闭担保。
    GuaranteeAutoAcceptanceCase(
        use_case_no="3.2",
        case_id="AUTO-ACCEPT-GUARANTEE-DISPATCH-PRICE-80000",
        title="担保开启后80000发单价私单待接单并在丸友集可见",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        workshop_name="旺仔工作室",
        strategy_name="指定-旺仔",
        strategy_type="单平台指定",
        sub_order_title_suffix="担保私单标识",
        receive_price="80000",
        dispatch_price="80000",
        expected_wanzhanggui_statuses=("待接单",),
        verify_mode="hall",
    ),
    # 用例3.3：检查担保已开启，若关闭则开启；独立创建一笔子单保证金80000的担保私单，结束后关闭担保。
    GuaranteeAutoAcceptanceCase(
        use_case_no="3.3",
        case_id="AUTO-ACCEPT-GUARANTEE-DEPOSIT-80000",
        title="担保开启后子单保证金80000私单待接单并在丸友集可见",
        wanzhanggui_phone="17788888888",
        wanyouji_phone="18800000001",
        workshop_name="旺仔工作室",
        strategy_name="指定-旺仔",
        strategy_type="单平台指定",
        sub_order_title_suffix="担保私单标识",
        security_deposit="80000",
        expected_wanzhanggui_statuses=("待接单",),
        verify_mode="hall",
        close_guarantee_after_case=True,
    ),
]


def create_auto_acceptance_order(
    order_page: WanzhangguiOrderPage,
    case: AutoAcceptanceCase,
    wanzhanggui_password: str,
    bug_reporter,
    *,
    status_id: str,
) -> dict[str, str]:
    timestamp = datetime.now().strftime("%m%d%H%M%S")
    source_order_no = (
        os.getenv(f"E2E_{case.case_id}_SOURCE_ORDER_NO", "").strip()
        or os.getenv("E2E_AUTO_ACCEPTANCE_SOURCE_ORDER_NO", "").strip()
        or f"AAORDER{timestamp}"
    )
    order_title = (
        os.getenv(f"E2E_{case.case_id}_ORDER_TITLE", "").strip()
        or os.getenv("E2E_AUTO_ACCEPTANCE_ORDER_TITLE", "").strip()
        or f"E2E自动接单{timestamp}"
    )
    if status_id:
        suffix = "".join(ch for ch in status_id.upper() if ch.isalnum())[:6]
        source_order_no = f"{source_order_no}{suffix}"
        order_title = f"{order_title}{suffix}"

    order = ManualOrderData(
        source_order_no=source_order_no,
        order_title=order_title,
        sub_order_title=f"{order_title}{case.sub_order_title_suffix}",
        strategy_name=case.strategy_name,
        strategy_type=case.strategy_type,
        role_name=f"AA角色{timestamp[-4:]}",
    )

    order_page.login_main_account(case.wanzhanggui_phone, wanzhanggui_password)
    bug_reporter.record_if_errors(
        account=case.wanzhanggui_phone,
        location=f"{case.case_id} 丸掌柜主账号登录",
    )
    order_page.create_manual_order(order)
    bug_reporter.record_if_errors(
        account=case.wanzhanggui_phone,
        location=f"{case.case_id} 丸掌柜手工录单并选择策略 {case.strategy_name}: {source_order_no}",
    )

    row_text = ""
    if case.expected_scope == "私单":
        row_text = order_page.refresh_order_list_and_get_row_text(source_order_no, order_title)
        bug_reporter.record_if_errors(
            account=case.wanzhanggui_phone,
            location=f"{case.case_id} 丸掌柜订单列表刷新查看私单状态 {source_order_no}",
        )
    return {"source_order_no": source_order_no, "order_title": order_title, "row_text": row_text}


def verify_private_order_waiting_in_hall(
    fulfillment_page: WanyoujiFulfillmentPage,
    case: AutoAcceptanceCase,
    wanyouji_password: str,
    source_order_no: str,
    order_title: str,
    bug_reporter,
) -> None:
    fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_password)
    fulfillment_page.verify_order_reached_hall(source_order_no, order_title, "私单")
    bug_reporter.record_if_errors(
        account=case.wanyouji_phone,
        location=f"{case.case_id} 丸友集抢单大厅-私单可见 {source_order_no}",
    )


def verify_private_order_accepted(
    fulfillment_page: WanyoujiFulfillmentPage,
    case: AutoAcceptanceCase,
    wanyouji_password: str,
    source_order_no: str,
    order_title: str,
    bug_reporter,
) -> str:
    fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_password)
    row_text = fulfillment_page.verify_workshop_order_list_status(source_order_no, order_title, ["已接单", "接单"])
    bug_reporter.record_if_errors(
        account=case.wanyouji_phone,
        location=f"{case.case_id} 丸友集订单列表验证私单已接单 {source_order_no}",
    )
    return row_text


def mark_auto_acceptance_order_dispatched(
    store,
    case: AutoAcceptanceCase,
    source_order_no: str,
    order_title: str,
) -> None:
    store.mark_order_dispatched(
        wanzhanggui_phone=case.wanzhanggui_phone,
        source_order_no=source_order_no,
        order_title=order_title,
        strategy_name=case.strategy_name,
        strategy_type=case.strategy_type,
        wanyouji_phones=[case.wanyouji_phone],
    )


@pytest.mark.e2e_auto_acceptance
@pytest.mark.e2e_ledger
@pytest.mark.e2e_chain
@pytest.mark.parametrize("case", CASES, ids=[case.case_id for case in CASES])
def test_自动接单用例_普通单发单和分支校验(
    page: Page,
    settings,
    bug_reporter,
    case: AutoAcceptanceCase,
) -> None:
    store = account_store()
    wanzhanggui_account = store.find(phone=case.wanzhanggui_phone)
    wanyouji_account = store.find(phone=case.wanyouji_phone)
    assert wanzhanggui_account is not None, f"台账中未找到丸掌柜账号 {case.wanzhanggui_phone}"
    assert wanyouji_account is not None, f"台账中未找到丸友集账号 {case.wanyouji_phone}"
    assert wanzhanggui_account.wanzhanggui_status == "opened", (
        f"丸掌柜账号 {case.wanzhanggui_phone} 未开通丸掌柜，当前状态：{wanzhanggui_account.wanzhanggui_status}"
    )
    assert wanyouji_account.wanyouji_status == "opened", (
        f"丸友集账号 {case.wanyouji_phone} 未开通丸友集，当前状态：{wanyouji_account.wanyouji_status}"
    )

    order_page = WanzhangguiOrderPage(page, settings.tenant_home_url, bug_reporter)
    fulfillment_page = WanyoujiFulfillmentPage(page, settings.tenant_home_url, bug_reporter)
    try:
        if case.verify_mode == "branch" and case.merchant_name:
            fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
            fulfillment_page.ensure_auto_accept_assignment(case.merchant_name, enabled=False)
            bug_reporter.record_if_errors(
                account=case.wanyouji_phone,
                location=f"{case.case_id} 丸友集关闭{case.merchant_name}自动接指派单",
            )
            waiting_order = create_auto_acceptance_order(
                order_page,
                case,
                wanzhanggui_account.password,
                bug_reporter,
                status_id="case12",
            )
            assert "待接单" in waiting_order["row_text"], (
                f"关闭自动接指派单后丸掌柜订单未保持待接单；"
                f"source_order_no={waiting_order['source_order_no']}; row_text={waiting_order['row_text'][:1500]}"
            )
            verify_private_order_waiting_in_hall(
                fulfillment_page,
                case,
                wanyouji_account.password,
                waiting_order["source_order_no"],
                waiting_order["order_title"],
                bug_reporter,
            )

            fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
            fulfillment_page.ensure_auto_accept_assignment(case.merchant_name, enabled=True)
            bug_reporter.record_if_errors(
                account=case.wanyouji_phone,
                location=f"{case.case_id} 丸友集开启{case.merchant_name}自动接指派单",
            )
            accepted_order = create_auto_acceptance_order(
                order_page,
                case,
                wanzhanggui_account.password,
                bug_reporter,
                status_id="case11",
            )
            assert "代练中" in accepted_order["row_text"], (
                f"开启自动接指派单后丸掌柜订单未进入代练中；"
                f"source_order_no={accepted_order['source_order_no']}; row_text={accepted_order['row_text'][:1500]}"
            )
            verify_private_order_accepted(
                fulfillment_page,
                case,
                wanyouji_account.password,
                accepted_order["source_order_no"],
                accepted_order["order_title"],
                bug_reporter,
            )
            mark_auto_acceptance_order_dispatched(store, case, waiting_order["source_order_no"], waiting_order["order_title"])
            mark_auto_acceptance_order_dispatched(store, case, accepted_order["source_order_no"], accepted_order["order_title"])
            return

        if case.verify_mode == "hall" and case.merchant_name:
            fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
            fulfillment_page.ensure_auto_accept_assignment(case.merchant_name, enabled=False)
            order_info = create_auto_acceptance_order(
                order_page,
                case,
                wanzhanggui_account.password,
                bug_reporter,
                status_id="case12",
            )
            assert "待接单" in order_info["row_text"], (
                f"关闭自动接指派单后丸掌柜订单未保持待接单；"
                f"source_order_no={order_info['source_order_no']}; row_text={order_info['row_text'][:1500]}"
            )
            verify_private_order_waiting_in_hall(
                fulfillment_page,
                case,
                wanyouji_account.password,
                order_info["source_order_no"],
                order_info["order_title"],
                bug_reporter,
            )
            mark_auto_acceptance_order_dispatched(store, case, order_info["source_order_no"], order_info["order_title"])
            return

        if case.verify_mode == "accepted" and case.merchant_name:
            fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
            fulfillment_page.ensure_auto_accept_assignment(case.merchant_name, enabled=True)
            order_info = create_auto_acceptance_order(
                order_page,
                case,
                wanzhanggui_account.password,
                bug_reporter,
                status_id="case11",
            )
            assert "代练中" in order_info["row_text"], (
                f"开启自动接指派单后丸掌柜订单未进入代练中；"
                f"source_order_no={order_info['source_order_no']}; row_text={order_info['row_text'][:1500]}"
            )
            verify_private_order_accepted(
                fulfillment_page,
                case,
                wanyouji_account.password,
                order_info["source_order_no"],
                order_info["order_title"],
                bug_reporter,
            )
            mark_auto_acceptance_order_dispatched(store, case, order_info["source_order_no"], order_info["order_title"])
            return

        order_info = create_auto_acceptance_order(
            order_page,
            case,
            wanzhanggui_account.password,
            bug_reporter,
            status_id="pool",
        )
        fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
        fulfillment_page.verify_order_reached_hall(order_info["source_order_no"], order_info["order_title"], case.expected_scope)
        bug_reporter.record_if_errors(
            account=case.wanyouji_phone,
            location=f"{case.case_id} 丸友集抢单大厅-{case.expected_scope} 验证订单 {order_info['source_order_no']}",
        )
        mark_auto_acceptance_order_dispatched(store, case, order_info["source_order_no"], order_info["order_title"])
    finally:
        if case.merchant_name:
            try:
                fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
                fulfillment_page.ensure_auto_accept_assignment(case.merchant_name, enabled=True)
                bug_reporter.record_if_errors(
                    account=case.wanyouji_phone,
                    location=f"{case.case_id} 收尾确认{case.merchant_name}自动接指派单开启",
                )
            except Exception as exc:
                if bug_reporter:
                    bug_reporter.record_if_errors(
                        account=case.wanyouji_phone,
                        location=f"{case.case_id} 收尾开启{case.merchant_name}自动接指派单失败：{exc}",
                    )
                print(f"[E2E] 收尾开启{case.merchant_name}自动接指派单失败，需人工确认：{exc}")


@pytest.mark.e2e_auto_acceptance
@pytest.mark.e2e_ledger
@pytest.mark.e2e_chain
@pytest.mark.parametrize("case", GUARANTEE_CASES, ids=[case.case_id for case in GUARANTEE_CASES])
def test_自动接单用例_担保单发单和担保交易校验(
    page: Page,
    settings,
    bug_reporter,
    case: GuaranteeAutoAcceptanceCase,
) -> None:
    store = account_store()
    wanzhanggui_account = store.find(phone=case.wanzhanggui_phone)
    wanyouji_account = store.find(phone=case.wanyouji_phone)
    assert wanzhanggui_account is not None, f"台账中未找到丸掌柜账号 {case.wanzhanggui_phone}"
    assert wanyouji_account is not None, f"台账中未找到丸友集账号 {case.wanyouji_phone}"
    assert wanzhanggui_account.wanzhanggui_status == "opened", (
        f"丸掌柜账号 {case.wanzhanggui_phone} 未开通丸掌柜，当前状态：{wanzhanggui_account.wanzhanggui_status}"
    )
    assert wanyouji_account.wanyouji_status == "opened", (
        f"丸友集账号 {case.wanyouji_phone} 未开通丸友集，当前状态：{wanyouji_account.wanyouji_status}"
    )

    timestamp = datetime.now().strftime("%m%d%H%M%S")
    source_order_no = (
        os.getenv(f"E2E_{case.case_id}_SOURCE_ORDER_NO", "").strip()
        or os.getenv("E2E_AUTO_ACCEPTANCE_SOURCE_ORDER_NO", "").strip()
        or f"AAGUAR{timestamp}"
    )
    order_title = (
        os.getenv(f"E2E_{case.case_id}_ORDER_TITLE", "").strip()
        or os.getenv("E2E_AUTO_ACCEPTANCE_ORDER_TITLE", "").strip()
        or f"E2E担保自动接单{timestamp}"
    )
    order = ManualOrderData(
        source_order_no=source_order_no,
        order_title=order_title,
        sub_order_title=f"{order_title}{case.sub_order_title_suffix}",
        strategy_name=case.strategy_name,
        strategy_type=case.strategy_type,
        receive_price=case.receive_price,
        dispatch_price=case.dispatch_price,
        security_deposit=case.security_deposit,
        efficiency_deposit=case.efficiency_deposit,
        role_name=f"AAG角色{timestamp[-4:]}",
    )

    order_page = WanzhangguiOrderPage(page, settings.tenant_home_url, bug_reporter)
    try:
        order_page.login_main_account(case.wanzhanggui_phone, wanzhanggui_account.password)
        bug_reporter.record_if_errors(
            account=case.wanzhanggui_phone,
            location=f"{case.case_id} 丸掌柜主账号登录",
        )
        order_page.ensure_workshop_guarantee(case.workshop_name, enabled=True)
        bug_reporter.record_if_errors(
            account=case.wanzhanggui_phone,
            location=f"{case.case_id} 开启工作室担保 {case.workshop_name}",
        )
        order_page.create_manual_order(order)
        bug_reporter.record_if_errors(
            account=case.wanzhanggui_phone,
            location=f"{case.case_id} 丸掌柜担保手工录单 {source_order_no}",
        )

        row_text = order_page.assert_order_list_status(
            source_order_no,
            order_title,
            list(case.expected_wanzhanggui_statuses),
        )
        if "代练中" not in row_text:
            assert "待接单" in row_text, (
                f"担保单创建后丸掌柜订单状态不符合预期；source_order_no={source_order_no}; row_text={row_text[:1500]}"
            )
        bug_reporter.record_if_errors(
            account=case.wanzhanggui_phone,
            location=f"{case.case_id} 丸掌柜担保订单列表状态 {source_order_no}",
        )

        if case.verify_mode == "trade_amount" and "代练中" not in row_text:
            pytest.skip(f"{case.case_id} 前置分支未满足：丸掌柜订单未进入代练中，当前行={row_text[:500]}")

        if case.verify_mode == "trade_amount" and "代练中" in row_text:
            fulfillment_order_no = order_page.extract_fulfillment_order_no_from_current_wanzhanggui_order_list(
                order_page.order_frame(),
                source_order_no,
                order_title,
            )
            order_page.verify_guarantee_trade_amount(
                fulfillment_order_no,
                case.dispatch_price,
            )
            bug_reporter.record_if_errors(
                account=case.wanzhanggui_phone,
                location=f"{case.case_id} 丸掌柜担保交易金额校验 {fulfillment_order_no}",
            )
        else:
            fulfillment_page = WanyoujiFulfillmentPage(page, settings.tenant_home_url, bug_reporter)
            fulfillment_page.login_main_account(case.wanyouji_phone, wanyouji_account.password)
            bug_reporter.record_if_errors(
                account=case.wanyouji_phone,
                location=f"{case.case_id} 丸友集主账号登录",
            )

        if case.verify_mode != "trade_amount":
            fulfillment_page.verify_order_reached_hall(source_order_no, order_title, "私单")
            bug_reporter.record_if_errors(
                account=case.wanyouji_phone,
                location=f"{case.case_id} 丸友集抢单大厅-私单可见 {source_order_no}",
            )

        store.mark_order_dispatched(
            wanzhanggui_phone=case.wanzhanggui_phone,
            source_order_no=source_order_no,
            order_title=order_title,
            strategy_name=case.strategy_name,
            strategy_type=case.strategy_type,
            wanyouji_phones=[case.wanyouji_phone],
        )
    finally:
        if case.close_guarantee_after_case:
            try:
                try:
                    order_page.login_main_account(case.wanzhanggui_phone, wanzhanggui_account.password)
                except Exception:
                    order_page.clear_login_state()
                    order_page.login_main_account(case.wanzhanggui_phone, wanzhanggui_account.password)
                for attempt in range(2):
                    try:
                        order_page.ensure_workshop_guarantee(case.workshop_name, enabled=False)
                        break
                    except Exception:
                        if attempt:
                            raise
                        order_page.clear_login_state()
                        order_page.login_main_account(case.wanzhanggui_phone, wanzhanggui_account.password)
                bug_reporter.record_if_errors(
                    account=case.wanzhanggui_phone,
                    location=f"{case.case_id} 关闭工作室担保 {case.workshop_name}",
                )
            except Exception as exc:
                if bug_reporter:
                    bug_reporter.record_if_errors(
                        account=case.wanzhanggui_phone,
                        location=f"{case.case_id} 关闭工作室担保失败：{exc}",
                    )
                print(f"[E2E] 关闭工作室担保失败，需人工确认担保状态：{exc}")
