import random
import re
from typing import Dict, List

from playwright.sync_api import Page, TimeoutError as PlaywrightTimeoutError

from dulizhan.test_case.Resource.UI.base_page import BasePage


class NewsPage(BasePage):
    """Joyhub News 相关页面对象。"""

    COOKIE_ACCEPT_TEXT_PATTERN = re.compile(r"^(Accepet|Accept|I Accept|Agree|Got it)$", re.I)
    NEWS_LINK_TEXT_PATTERN = re.compile(r"^News$", re.I)
    NEWS_ROUTE = "/news"

    def __init__(self, page: Page, base_url: str):
        super().__init__(page)
        self.base_url = base_url.rstrip("/")

    def open_home(self) -> None:
        self.goto(self.base_url)

    def accept_cookie_if_present(self) -> None:
        accept_button = self.page.get_by_role("button", name=self.COOKIE_ACCEPT_TEXT_PATTERN)
        self.click_if_visible(accept_button, timeout=3000)

    def enter_news_page(self) -> None:
        news_link = self.page.get_by_role("link", name=self.NEWS_LINK_TEXT_PATTERN)

        try:
            if news_link.first.is_visible(timeout=5000):
                news_link.first.click()
                self.wait_for_network_idle()
                return
        except Exception:
            pass

        self.goto(f"{self.base_url}{self.NEWS_ROUTE}")

    def is_news_context(self) -> bool:
        url = self.page.url.lower()
        title = self.page.title().lower()

        if "news" in url:
            return True
        if "news" in title:
            return True
        if self.visible_text_contains("News"):
            return True

        return False

    def _collect_clickable_news_candidates(self) -> List[Dict[str, str]]:
        script = """
        () => {
            const navTexts = new Set([
                'home',
                'download the app',
                'rewards',
                'support',
                'about us',
                'discover',
                'following',
                'partnerships',
                'faqs',
                'login'
            ]);

            const currentUrl = new URL(window.location.href);
            const anchors = Array.from(document.querySelectorAll('a[href]'));

            function isVisible(el) {
                const style = window.getComputedStyle(el);
                const rect = el.getBoundingClientRect();
                return style &&
                    style.visibility !== 'hidden' &&
                    style.display !== 'none' &&
                    rect.width > 0 &&
                    rect.height > 0;
            }

            function hasContentContainer(el) {
                return !!el.closest(
                    'article, [class*="article" i], [class*="card" i], [class*="news" i], [class*="post" i], [class*="blog" i], [class*="item" i]'
                );
            }

            function isBadProtocol(url) {
                return ['javascript:', 'mailto:', 'tel:'].includes(url.protocol);
            }

            function isLikelySocial(url) {
                const host = url.hostname.toLowerCase();
                return [
                    'facebook.com',
                    'instagram.com',
                    'twitter.com',
                    'x.com',
                    'youtube.com',
                    'tiktok.com',
                    'linkedin.com'
                ].some(domain => host.includes(domain));
            }

            const candidates = [];

            for (const a of anchors) {
                if (!isVisible(a)) continue;

                let url;
                try {
                    url = new URL(a.href, window.location.origin);
                } catch (e) {
                    continue;
                }

                if (isBadProtocol(url)) continue;
                if (isLikelySocial(url)) continue;
                if (url.href === currentUrl.href) continue;

                const text = (a.innerText || a.textContent || '').trim().replace(/\\s+/g, ' ');
                const textLower = text.toLowerCase();
                const pathLower = url.pathname.toLowerCase();

                if (navTexts.has(textLower)) continue;
                if (url.pathname === '/' || url.pathname === '') continue;

                const hrefLooksLikeContent =
                    /news|article|blog|post|detail|story/i.test(pathLower) &&
                    pathLower !== '/news';

                const containerLooksLikeContent = hasContentContainer(a);

                if (hrefLooksLikeContent || containerLooksLikeContent) {
                    candidates.push({
                        href: url.href,
                        text: text,
                        path: url.pathname,
                        reason: hrefLooksLikeContent ? 'href_content_pattern' : 'content_container'
                    });
                }
            }

            const seen = new Set();
            return candidates.filter(item => {
                if (seen.has(item.href)) return false;
                seen.add(item.href);
                return true;
            });
        }
        """
        return self.page.evaluate(script)

    def click_random_news_item(self) -> Dict[str, str]:
        self.wait_for_network_idle()
        candidates = self._collect_clickable_news_candidates()

        if not candidates:
            raise AssertionError(
                "未发现可点击的 news 内容候选。"
                "请检查 News 页面是否加载成功，或为 news 卡片补充稳定 selector/data-testid。"
            )

        selected = random.choice(candidates)
        href = selected["href"]
        old_url = self.page.url

        click_script = """
        (targetHref) => {
            const anchors = Array.from(document.querySelectorAll('a[href]'));
            const target = anchors.find(a => {
                try {
                    return new URL(a.href, window.location.origin).href === targetHref;
                } catch (e) {
                    return false;
                }
            });

            if (!target) {
                throw new Error('Target news link not found: ' + targetHref);
            }

            target.scrollIntoView({block: 'center', inline: 'center'});
            target.click();
        }
        """

        self.page.evaluate(click_script, href)

        try:
            self.page.wait_for_url(lambda url: str(url) != old_url, timeout=15000)
        except PlaywrightTimeoutError:
            pass

        self.wait_for_network_idle()
        return selected

    def screenshot_news_content(self, screenshot_dir: str, file_name: str) -> str:
        return self.screenshot(screenshot_dir=screenshot_dir, file_name=file_name, full_page=True)
