from __future__ import annotations

import os
from typing import Any

import pytest
from playwright.sync_api import Page

from e2e.pages.wanyouji_member_page import WanyoujiMemberData, WanyoujiMemberPage
from e2e.pages.wanzhanggui_order_page import WanyoujiFulfillmentPage
from e2e.utils.account_store import E2EAccount, account_store
from e2e.utils.dual_browser import assert_account_page, dual_browser_enabled, dual_browser_manager
from e2e.utils.verification_code import FeishuConfig, VerificationCodeProvider


@pytest.mark.e2e_task_001
@pytest.mark.e2e_ledger
@pytest.mark.e2e_chain
def test_丸掌柜外部派单由丸友集接单并发到打手抢单大厅(page: Page, settings, bug_reporter) -> None:
    wanzhanggui_phone = os.getenv("E2E_TASK_WANZHANGGUI_PHONE", settings.wanzhanggui_tenant_phone)
    assignment_method = os.getenv("E2E_TASK_ASSIGNMENT_METHOD", "抢单大厅").strip()
    assert assignment_method in {"抢单大厅", "指派打手", "智能派单"}, (
        "E2E_TASK_ASSIGNMENT_METHOD 仅支持：抢单大厅、指派打手、智能派单；"
        f"当前值：{assignment_method}"
    )

    store = account_store()
    order, wanyouji_account, player_account = resolve_task_order_and_accounts(wanzhanggui_phone)
    expected_scope = "私单" if order.get("strategy_type") == "单平台指定" else "公池单/私单"
    source_order_no = order["source_order_no"]
    order_title = order["order_title"]

    fulfillment_page = WanyoujiFulfillmentPage(page, settings.tenant_home_url, bug_reporter)
    fulfillment_page.login_main_account(wanyouji_account.phone, wanyouji_account.password)
    bug_reporter.record_if_errors(account=wanyouji_account.phone, location="丸友集主账号登录")

    if order.get("status") in {"task_dispatched_to_player_hall", "task_player_accepted"}:
        accepted_scope = order.get("task_accept_scope", "已接单")
    elif order.get("status") == "task_accepted":
        accepted_scope = order.get("task_accept_scope", "已接单")
    else:
        accepted_scope = fulfillment_page.accept_external_order_from_hall(source_order_no, order_title, expected_scope)
        store.mark_task_order_status(
            source_order_no=source_order_no,
            status="task_accepted",
            task_accept_scope=accepted_scope,
            task_wanyouji_phone=wanyouji_account.phone,
        )
        bug_reporter.record_if_errors(
            account=wanyouji_account.phone,
            location=(
                "丸友集-工作室履约应用-抢单大厅-"
                f"{accepted_scope}-立即接单：{source_order_no}/{order_title}"
            ),
        )

    if order.get("status") not in {"task_dispatched_to_player_hall", "task_player_accepted"}:
        fulfillment_page.dispatch_workshop_order_to_player_hall(
            source_order_no,
            order_title,
            assignment_method=assignment_method,
            player_name=player_account.contact_name if assignment_method == "指派打手" else "",
            player_phone=player_account.phone if assignment_method == "指派打手" else "",
        )
        store.mark_task_order_status(
            source_order_no=source_order_no,
            status="task_dispatched_to_player_hall",
            task_assignment_method=assignment_method,
            task_player_phone=player_account.phone,
        )
        bug_reporter.record_if_errors(
            account=wanyouji_account.phone,
            location=(
                "丸友集-工作室履约应用-订单列表-立即发单-"
                f"{assignment_method}：{source_order_no}/{order_title}"
            ),
        )

    player_browser_page = login_player_sub_account_by_sms(page, settings, bug_reporter, player_account)
    player_page = WanyoujiFulfillmentPage(player_browser_page, settings.tenant_home_url, bug_reporter)
    if order.get("status") == "task_player_accepted" or assignment_method in {"指派打手", "智能派单"}:
        player_page.verify_order_in_player_my_orders(source_order_no, order_title)
        store.mark_task_order_status(
            source_order_no=source_order_no,
            status="task_player_accepted",
            task_player_phone=player_account.phone,
        )
    else:
        player_page.grab_order_from_player_hall_and_verify_my_order(source_order_no, order_title)
        store.mark_task_order_status(
            source_order_no=source_order_no,
            status="task_player_accepted",
            task_player_phone=player_account.phone,
        )
    bug_reporter.record_if_errors(
        account=player_account.phone,
        location=(
            "丸友集-打手应用-抢单大厅-立即抢单-我的订单验证："
            f"{source_order_no}/{order_title}"
        ),
    )


def resolve_task_order_and_accounts(wanzhanggui_phone: str) -> tuple[dict[str, Any], E2EAccount, E2EAccount]:
    store = account_store()
    explicit_order_no = os.getenv("E2E_TASK_SOURCE_ORDER_NO", "").strip()
    explicit_wanyouji_phone = os.getenv("E2E_TASK_WANYOUJI_PHONE", "").strip()
    explicit_player_phone = os.getenv("E2E_TASK_PLAYER_PHONE", "").strip()
    strategy_type = os.getenv("E2E_TASK_STRATEGY_TYPE", "").strip()

    if explicit_order_no:
        orders = [
            item
            for item in store.load_payload().get("dispatched_orders", [])
            if item.get("wanzhanggui_phone") == wanzhanggui_phone
            and item.get("source_order_no") == explicit_order_no
            and item.get("status")
            in {"dispatched", "task_accepted", "task_dispatched_to_player_hall", "task_player_accepted"}
        ]
    else:
        orders = [
            item
            for item in store.load_payload().get("dispatched_orders", [])
            if item.get("wanzhanggui_phone") == wanzhanggui_phone
            and item.get("status")
            in {"dispatched", "task_accepted", "task_dispatched_to_player_hall", "task_player_accepted"}
            and (not strategy_type or item.get("strategy_type") == strategy_type)
        ]
    orders = sorted(orders, key=lambda item: item.get("created_at", ""), reverse=True)
    assert orders, "台账中没有可用于 E2E-TASK-001 的丸掌柜已派单订单，请先执行 push_003 + order_001。"

    accounts = {account.phone: account for account in store.load()}
    for order in orders:
        candidate_wanyouji_phones = list(order.get("wanyouji_phones", []))
        if order.get("status") in {"task_accepted", "task_dispatched_to_player_hall", "task_player_accepted"}:
            candidate_wanyouji_phones = [order.get("task_wanyouji_phone", "")]
        if explicit_wanyouji_phone:
            candidate_wanyouji_phones = [explicit_wanyouji_phone]
        for wanyouji_phone in candidate_wanyouji_phones:
            wanyouji_account = accounts.get(wanyouji_phone)
            if not wanyouji_account:
                continue
            player_account = find_player_account(wanyouji_account, explicit_player_phone)
            if player_account:
                return order, wanyouji_account, player_account

    raise AssertionError(
        "未找到同时满足“已接收丸掌柜派单”且“企业下存在已审批打手子账号”的丸友集账号；"
        "可通过 E2E_TASK_WANYOUJI_PHONE / E2E_TASK_PLAYER_PHONE / E2E_TASK_SOURCE_ORDER_NO 指定。"
    )


def find_player_account(parent: E2EAccount, explicit_player_phone: str = "") -> E2EAccount | None:
    for account in reversed(account_store().load()):
        if explicit_player_phone and account.phone != explicit_player_phone:
            continue
        if account.account_type != "sub":
            continue
        if account.parent_phone != parent.phone:
            continue
        if account.member_role != "打手":
            continue
        if account.member_status not in {"approved", "registered"}:
            continue
        return account
    return None


def login_player_sub_account_by_sms(page: Page, settings, bug_reporter, player: E2EAccount) -> Page:
    if dual_browser_enabled():
        page = dual_browser_manager().page_for_account(player.phone, seed_page=page)
        if bug_reporter:
            bug_reporter.bind_page(page)
    if can_reuse_player_login(page, player):
        if bug_reporter:
            bug_reporter.clear()
        return page

    code_provider = VerificationCodeProvider(
        mode=settings.verification_code_mode,
        static_code=settings.verification_code_static,
        manual_code_file=settings.manual_code_file,
        manual_timeout_seconds=settings.manual_code_timeout_seconds,
        manual_poll_interval_seconds=settings.manual_code_poll_interval_seconds,
        feishu_config=FeishuConfig(
            app_id=settings.feishu_app_id,
            app_secret=settings.feishu_app_secret,
            chat_id=settings.feishu_chat_id,
            timeout_seconds=settings.feishu_timeout_seconds,
            poll_interval_seconds=settings.feishu_poll_interval_seconds,
        ),
    )
    member_page = WanyoujiMemberPage(
        page,
        settings.tenant_home_url,
        bug_reporter,
        code_provider=code_provider,
    )
    member = WanyoujiMemberData(
        phone=player.phone,
        password=player.password,
        role="打手",
        name=player.contact_name,
        product="丸友集",
    )
    member_page.verify_member_can_login_by_sms(member)
    setattr(page, "_e2e_current_player_account", player.phone)
    setattr(page, "_e2e_current_main_account", "")
    if dual_browser_enabled():
        dual_browser_manager().set_active_page(page)
        assert_account_page(page, player.phone)
    return page


def can_reuse_player_login(page: Page, player: E2EAccount) -> bool:
    if os.getenv("E2E_REUSE_PLAYER_LOGIN", "").lower() not in {"1", "true", "yes"}:
        return False
    if getattr(page, "_e2e_current_player_account", "") != player.phone:
        return False
    try:
        page.goto("https://test-merchant-lianlianyun.lianlianwz.com/productConsole?productCode=P20250814095939369041")
        page.wait_for_load_state("domcontentloaded")
        page.wait_for_timeout(1500)
        text = page.locator("body").inner_text(timeout=5000)
        return "打手应用" in text and ("我的订单" in text or "我的收入" in text or player.contact_name in text)
    except Exception:
        return False
