from __future__ import annotations

import json
import os
import re
import sys
from pathlib import Path

from dotenv import load_dotenv
from playwright.sync_api import sync_playwright

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from e2e.pages.wanzhanggui_order_page import WanzhangguiOrderPage
from e2e.utils.account_store import account_store


TENANT_HOME_URL = os.getenv("TENANT_HOME_URL", "https://test-lianlianyun.lianlianwz.com/home")
OUTPUT_PATH = Path("runtime/recent_s_flow_order_candidates.json")


def main() -> None:
    load_dotenv()
    wanzhanggui_phone = os.getenv("E2E_ORDER_WANZHANGGUI_PHONE", "19147509308")
    wanzhanggui_password = os.getenv("E2E_ORDER_WANZHANGGUI_PASSWORD", "test123456")
    viewport_width = int(os.getenv("E2E_VIEWPORT_WIDTH", "1920"))
    viewport_height = int(os.getenv("E2E_VIEWPORT_HEIGHT", "1080"))

    store = account_store()
    wanyouji_phones = [
        account.phone
        for account in store.load()
        if account.certification_status == "approved"
        and account.wanyouji_status == "opened"
        and any(
            item.get("wanzhanggui_phone") == wanzhanggui_phone and item.get("status") == "authorized"
            for item in account.workshop_authorizations
        )
    ][:2]

    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(
            headless=False,
            args=[f"--window-size={viewport_width},{viewport_height}"],
        )
        context = browser.new_context(
            viewport={"width": viewport_width, "height": viewport_height},
            screen={"width": viewport_width, "height": viewport_height},
        )
        page = context.new_page()
        order_page = WanzhangguiOrderPage(page, TENANT_HOME_URL)
        order_page.login_main_account(wanzhanggui_phone, wanzhanggui_password)
        frame = order_page.open_order_management()
        page.wait_for_timeout(2000)

        rows = collect_all_pages(frame)
        for keyword in search_keywords():
            order_page.search_order_if_possible(frame, keyword)
            page.wait_for_timeout(2000)
            keyword_rows = extract_order_rows(frame)
            for row in keyword_rows:
                row["query_keyword"] = keyword
            rows.extend(keyword_rows)
        candidates = [row for row in rows if is_without_dispatch_candidate(row)]
        selected = unique_orders(candidates)[:2]

        for row in selected:
            store.mark_order_without_dispatch(
                wanzhanggui_phone=wanzhanggui_phone,
                main_order_no=row.get("main_order_no", ""),
                source_order_no=row.get("source_order_no", ""),
                order_title=row.get("order_title", ""),
                wanyouji_phones=wanyouji_phones,
            )

        OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
        OUTPUT_PATH.write_text(
            json.dumps({"selected": selected, "candidates": candidates, "visible_rows": rows}, ensure_ascii=False, indent=2),
            encoding="utf-8",
        )
        print(json.dumps({"recorded": selected, "candidate_count": len(candidates)}, ensure_ascii=False, indent=2))
        context.close()
        browser.close()


def extract_order_rows(frame) -> list[dict[str, str]]:
    raw_rows = frame.evaluate(
        """() => Array.from(document.querySelectorAll('.ant-table-tbody tr, tr.ant-table-row'))
          .map(row => (row.innerText || row.textContent || '').trim())
          .filter(Boolean)"""
    )
    rows: list[dict[str, str]] = []
    for text in raw_rows:
        main_order_no = first_match(r"BO\d{8,}", text)
        source_order_no = first_match(r"E2EORDER\d+", text)
        source_order_no_full = first_match(r"E2EORDER\d{8,}", text)
        if source_order_no_full:
            source_order_no = source_order_no_full
        if not source_order_no:
            source_order_no = extract_after_label(text, "来源单号:")
        title = first_match(r"E2E[^\n\t]+", text)
        rows.append(
            {
                "main_order_no": main_order_no,
                "source_order_no": source_order_no,
                "order_title": title,
                "text": text,
            }
        )
    return rows


def collect_all_pages(frame) -> list[dict[str, str]]:
    all_rows: list[dict[str, str]] = []
    seen_pages: set[str] = set()
    for _ in range(8):
        rows = extract_order_rows(frame)
        page_signature = "\n".join(row.get("text", "")[:200] for row in rows)
        if page_signature in seen_pages:
            break
        seen_pages.add(page_signature)
        for row in rows:
            row["query_keyword"] = "<all-pages>"
        all_rows.extend(rows)
        if not click_next_page(frame):
            break
        frame.page.wait_for_timeout(1500)
    return all_rows


def click_next_page(frame) -> bool:
    return bool(
        frame.evaluate(
            """() => {
                const next = Array.from(document.querySelectorAll('.ant-pagination-next, li[title="下一页"], button'))
                  .map(el => ({ el, text: (el.innerText || el.textContent || '').trim(), cls: String(el.className || ''), disabled: el.getAttribute('aria-disabled') === 'true' || el.classList.contains('ant-pagination-disabled'), r: el.getBoundingClientRect() }))
                  .filter(item => item.r.width > 0 && item.r.height > 0)
                  .find(item => !item.disabled && (item.cls.includes('ant-pagination-next') || item.text === '下一页' || item.text === '>'));
                if (!next) return false;
                next.el.click();
                return true;
            }"""
        )
    )


def search_keywords() -> list[str]:
    explicit = os.getenv("E2E_S_FLOW_SEARCH_KEYWORDS", "").strip()
    if explicit:
        return [item.strip() for item in explicit.split(",") if item.strip()]
    return [
        "E2EORDER",
        "E2E手工录单",
    ]


def unique_orders(rows: list[dict[str, str]]) -> list[dict[str, str]]:
    seen: set[tuple[str, str, str]] = set()
    unique: list[dict[str, str]] = []
    for row in rows:
        key = (row.get("main_order_no", ""), row.get("source_order_no", ""), row.get("order_title", ""))
        if key in seen:
            continue
        seen.add(key)
        unique.append(row)
    return unique


def is_without_dispatch_candidate(row: dict[str, str]) -> bool:
    text = row.get("text", "")
    if not row.get("main_order_no"):
        return False
    if "待接单" not in text:
        return False
    if "推单价" in text:
        return False
    if "\n-\n\t14" not in text and "\n-\n\t" not in text and "接单供应链" not in text:
        return False
    return True


def first_match(pattern: str, text: str) -> str:
    match = re.search(pattern, text)
    return match.group(0) if match else ""


def extract_after_label(text: str, label: str) -> str:
    index = text.find(label)
    if index < 0:
        return ""
    value = text[index + len(label) :].strip().splitlines()[0].strip()
    return value.replace("...", "")


if __name__ == "__main__":
    main()
