from __future__ import annotations

from playwright.sync_api import Page, expect

from e2e.pages.base_page import BasePage
from e2e.pages.tenant_registration_page import TenantRegistrationPage
from e2e.utils.bug_reporter import BugReporter


class TenantSubscriptionPage(BasePage):
    def __init__(
        self,
        page: Page,
        home_url: str,
        tenant_login: TenantRegistrationPage,
        bug_reporter: BugReporter | None = None,
    ):
        super().__init__(page)
        self.home_url = home_url
        self.tenant_login = tenant_login
        self.bug_reporter = bug_reporter

    def login_certified_tenant(self, phone: str, password: str) -> None:
        if self.current_session_ready():
            return
        self.login(phone, password)
        self.select_default_account_if_present()
        self.page.wait_for_function(
            """() => Array.from(document.querySelectorAll('taro-view-core, div, span'))
                .some(el => {
                    const text = (el.innerText || el.textContent || '').trim();
                    const r = el.getBoundingClientRect();
                    return text === '进入后台' && r.width > 0 && r.height > 0;
                })""",
            timeout=10000,
        )

    def login(self, phone: str, password: str) -> None:
        self.open_login_form()
        if self.current_session_ready():
            return

        phone_input = self.page.locator("#password_login_phone")
        self.fill_and_verify(phone_input, phone)

        password_input = self.page.locator("#password_login_password")
        self.fill_and_verify(password_input, password)
        self.click_login_submit()
        self.page.wait_for_load_state("domcontentloaded")
        self.page.wait_for_timeout(2000)

    def current_session_ready(self) -> bool:
        try:
            body_text = self.page.locator("body").inner_text(timeout=3000)
        except Exception:
            return False
        return "进入后台" in body_text and "主账号" in body_text

    def click_login_submit(self) -> None:
        try:
            self.click_first_visible(
                [
                    "button[type='submit']:has-text('登 录')",
                    "button:has-text('登 录')",
                    ".ant-btn-primary:has-text('登 录')",
                ],
                timeout=3000,
            )
            return
        except AssertionError:
            pass
        self.click_visible_exact_text("登 录")

    def open_login_form(self) -> None:
        for attempt in range(4):
            if attempt == 0:
                self.clear_tenant_session()
                self.goto(self.home_url.replace("/home", "/login"))
            elif attempt == 1:
                self.goto(self.home_url)
                self.page.wait_for_load_state("domcontentloaded")
                self.page.wait_for_timeout(1500)
                self.maybe_click_visible_exact_text("登录/注册")
            elif attempt == 2:
                self.goto(self.home_url.replace("/home", "/login?tab=password"))
            else:
                self.page.reload(wait_until="domcontentloaded")

            self.page.wait_for_load_state("domcontentloaded")
            if self.wait_for_login_form(timeout=8000):
                return

        body_text = self.page.locator("body").inner_text(timeout=5000)
        if "进入后台" in body_text and "主账号" in body_text:
            return
        raise AssertionError(f"租户登录页未加载出账号密码登录表单，当前页面文本：{body_text[:1000]}")

    def clear_tenant_session(self) -> None:
        try:
            self.page.context.clear_cookies()
        except Exception:
            pass

    def wait_for_login_form(self, timeout: int = 10000) -> bool:
        try:
            self.page.wait_for_selector("#password_login_phone", state="visible", timeout=timeout)
            self.page.wait_for_selector("#password_login_password", state="visible", timeout=timeout)
            return True
        except Exception:
            return False

    def select_default_account_if_present(self) -> None:
        if "/account/select" not in self.page.url and "选择账号" not in self.page.locator("body").inner_text(timeout=3000):
            return

        selected = self.page.evaluate(
            """() => {
                const candidates = Array.from(document.querySelectorAll('taro-view-core, div'))
                    .filter(el => {
                        const text = el.innerText || el.textContent || '';
                        const r = el.getBoundingClientRect();
                        return r.width > 0 && r.height > 0 && text.includes('主账号');
                    });
                candidates.sort((a, b) => {
                    const ar = a.getBoundingClientRect();
                    const br = b.getBoundingClientRect();
                    return (ar.width * ar.height) - (br.width * br.height);
                });
                const target = candidates.find(el => {
                    const r = el.getBoundingClientRect();
                    return r.width > 80 && r.height > 30;
                });
                if (!target) return false;
                target.click();
                return true;
            }"""
        )
        if selected:
            self.page.wait_for_load_state("domcontentloaded")
            self.page.wait_for_timeout(2000)

    def open_subscription_page(self) -> None:
        self.goto(self.home_url)
        self.page.wait_for_load_state("domcontentloaded")
        self.select_default_account_if_present()
        self.page.wait_for_timeout(2000)
        if not self.maybe_click_visible_exact_text("订阅购买"):
            self.goto(self.home_url)
            self.page.wait_for_load_state("domcontentloaded")
            self.page.wait_for_timeout(3000)
            if not self.maybe_click_visible_exact_text("订阅购买"):
                self.goto(self.home_url.replace("/home", "/scheme"))
        self.page.wait_for_load_state("domcontentloaded")
        self.page.wait_for_timeout(1500)
        if not self.wait_for_solution_card("丸友集", timeout=10000):
            self.goto(self.home_url.replace("/home", "/scheme"))
            self.page.wait_for_load_state("domcontentloaded")
            self.page.wait_for_timeout(1500)
            body_text = self.page.locator("body").inner_text(timeout=5000)
            assert self.wait_for_solution_card("丸友集", timeout=10000) or "丸友集" in body_text, f"订阅购买页未加载出丸友集产品卡片，当前页面文本：{body_text[:1000]}"

    def click_visible_exact_text(self, text: str) -> None:
        if not self.maybe_click_visible_exact_text(text):
            raise AssertionError(f"未找到可见文本：{text}")

    def maybe_click_visible_exact_text(self, text: str) -> bool:
        clicked = self.page.evaluate(
            """text => {
                const target = Array.from(document.querySelectorAll('taro-view-core, div, span, button'))
                    .find(el => {
                        const value = (el.innerText || el.textContent || '').trim();
                        const r = el.getBoundingClientRect();
                        return value === text && r.width > 0 && r.height > 0;
                    });
                if (!target) return false;
                target.click();
                return true;
            }""",
            text,
        )
        return bool(clicked)

    def wait_for_solution_card(self, solution_name: str, timeout: int = 10000) -> bool:
        try:
            self.page.wait_for_function(
                """name => Array.from(document.querySelectorAll('[class*="solutionCard"]'))
                    .filter(el => !String(el.className).includes('solutionCards'))
                    .some(el => (el.innerText || el.textContent || '').includes(name))""",
                solution_name,
                timeout=timeout,
            )
            return True
        except Exception:
            return False

    def apply_wanyouji(self, account: str) -> None:
        self.apply_solution("丸友集", account)

    def apply_wanzhanggui(self, account: str) -> None:
        self.apply_solution("丸掌柜", account)

    def apply_solution(self, solution_name: str, account: str) -> None:
        self.open_subscription_page()
        status = self.solution_status(solution_name)
        if status in {"已开通", "审核中", "待审核", "已申请", "申请中"}:
            return

        self.click_solution_button(solution_name, ["申请开通", "立即开通", "免费开通"])
        self.page.wait_for_timeout(2000)
        self.confirm_product_opening_if_present()
        self.page.wait_for_timeout(2000)
        if self.bug_reporter:
            self.bug_reporter.record_if_errors(account=account, location=f"租户平台-订阅购买-申请开通{solution_name}")

    def confirm_product_opening_if_present(self) -> None:
        try:
            self.click_first_visible(
                [
                    ".ant-modal button:has-text('确认开通')",
                    ".ant-modal button:has-text('确定')",
                    ".ant-modal button:has-text('确认')",
                    "button:has-text('确认开通')",
                ],
                timeout=3000,
            )
            return
        except AssertionError:
            pass

        self.maybe_click_text(["确认开通", "确定", "确认", "提交", "我知道了"], timeout=1500)

    def solution_status(self, solution_name: str) -> str:
        text = self.solution_card_text(solution_name)
        for status in ("已开通", "审核中", "待审核", "已申请", "申请中", "申请开通"):
            if status in text:
                return status
        return ""

    def solution_card_text(self, solution_name: str) -> str:
        card_text = self.page.evaluate(
            """name => {
                const cards = Array.from(document.querySelectorAll('[class*="solutionCard"]'))
                    .filter(el => !String(el.className).includes('solutionCards'));
                const card = cards.find(el => (el.innerText || el.textContent || '').includes(name));
                return card ? (card.innerText || card.textContent || '') : '';
            }""",
            solution_name,
        )
        if card_text:
            return card_text

        body_text = self.page.locator("body").inner_text(timeout=5000)
        if solution_name not in body_text:
            return ""
        lines = [line.strip() for line in body_text.splitlines() if line.strip()]
        for index, line in enumerate(lines):
            if line == solution_name:
                return "\n".join(lines[index : index + 4])
        return body_text

    def click_solution_button(self, solution_name: str, button_texts: list[str]) -> None:
        scrolled = self.page.evaluate(
            """({ solutionName, buttonTexts }) => {
                const cards = Array.from(document.querySelectorAll('[class*="solutionCard"]'))
                    .filter(el => !String(el.className).includes('solutionCards'));
                const card = cards.find(el => (el.innerText || el.textContent || '').includes(solutionName));
                if (!card) return false;
                const target = Array.from(card.querySelectorAll('taro-view-core, div, span, button'))
                    .find(el => {
                        const text = (el.innerText || el.textContent || '').trim();
                        const r = el.getBoundingClientRect();
                        const cls = String(el.className);
                        return r.width > 0 && r.height > 0 && (
                            cls.includes('useButton___') ||
                            buttonTexts.some(item => text.includes(item)) ||
                            cls.includes('useButton')
                        );
                    });
                if (!target) return false;
                target.scrollIntoView({ block: 'center', inline: 'center' });
                return true;
            }""",
            {"solutionName": solution_name, "buttonTexts": button_texts},
        )
        if scrolled:
            self.page.wait_for_timeout(300)

        target_box = self.page.evaluate(
            """({ solutionName, buttonTexts }) => {
                const cards = Array.from(document.querySelectorAll('[class*="solutionCard"]'))
                    .filter(el => !String(el.className).includes('solutionCards'));
                const card = cards.find(el => (el.innerText || el.textContent || '').includes(solutionName));
                if (!card) return null;
                const candidates = Array.from(card.querySelectorAll('taro-view-core, div, span, button'))
                    .map(el => {
                        const text = (el.innerText || el.textContent || '').trim();
                        const r = el.getBoundingClientRect();
                        const cls = String(el.className);
                        return { el, text, cls, r };
                    })
                    .filter(item => {
                        return item.r.width > 0 && item.r.height > 0 && (
                            item.cls.includes('useButton___') ||
                            buttonTexts.some(text => item.text.includes(text)) ||
                            item.cls.includes('useButton')
                        );
                    });
                candidates.sort((a, b) => {
                    const score = item => {
                        if (item.cls.includes('useButton___')) return 0;
                        if (buttonTexts.includes(item.text)) return 1;
                        if (item.cls.includes('useButton')) return 2;
                        return 3;
                    };
                    return score(a) - score(b);
                });
                const target = candidates[0];
                if (!target) return null;
                return {
                    x: target.r.x,
                    y: target.r.y,
                    width: target.r.width,
                    height: target.r.height,
                    text: target.text,
                    className: target.cls
                };
            }""",
            {"solutionName": solution_name, "buttonTexts": button_texts},
        )
        if not target_box:
            card_text = self.solution_card_text(solution_name)
            raise AssertionError(f"未找到 {solution_name} 的按钮：{button_texts}，当前卡片文本：{card_text}")
        self.page.mouse.click(
            target_box["x"] + target_box["width"] / 2,
            target_box["y"] + target_box["height"] / 2,
        )

    def wanyouji_available(self) -> bool:
        return self.solution_available("丸友集")

    def wanzhanggui_available(self) -> bool:
        return self.solution_available("丸掌柜")

    def solution_available(self, solution_name: str) -> bool:
        self.open_subscription_page()
        status = self.solution_status(solution_name)
        if status == "已开通":
            return True

        card_text = self.solution_card_text(solution_name)
        return "进入管理后台" in card_text or "进入后台" in card_text

    def open_wanyouji_console(self) -> Page:
        self.open_subscription_page()
        before_pages = set(self.page.context.pages)
        self.click_solution_button("丸友集", ["进入管理后台", "进入后台"])
        self.page.wait_for_timeout(3000)
        new_pages = [page for page in self.page.context.pages if page not in before_pages]
        if new_pages:
            console_page = new_pages[-1]
            console_page.wait_for_load_state("domcontentloaded")
            return console_page
        self.page.wait_for_load_state("domcontentloaded")
        return self.page
