"""
Banner Detector — identifies Consent Management Platforms and their buttons.

Supports 10+ CMPs with specific selectors + generic fallback.
"""

from dataclasses import dataclass

from playwright.async_api import Page, Locator


@dataclass
class BannerInfo:
    detected: bool
    provider: str
    accept_selector: str
    reject_selector: str


# CMP-specific selectors (ordered by market share)
CMP_SELECTORS = [
    {
        "name": "Didomi",
        "detect": "#didomi-host, [class*='didomi']",
        "accept": "#didomi-notice-agree-button",
        "reject": "#didomi-notice-disagree-button, .didomi-components-button--secondary",
    },
    {
        "name": "OneTrust",
        "detect": "#onetrust-banner-sdk, [class*='onetrust']",
        "accept": "#onetrust-accept-btn-handler",
        "reject": "#onetrust-reject-all-handler, .onetrust-close-btn-handler",
    },
    {
        "name": "Cookiebot",
        "detect": "#CybotCookiebotDialog, [class*='CybotCookiebot']",
        "accept": "#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll",
        "reject": "#CybotCookiebotDialogBodyButtonDecline",
    },
    {
        "name": "Usercentrics",
        "detect": "#usercentrics-root, [data-testid='uc-banner']",
        "accept": "[data-testid='uc-accept-all-button']",
        "reject": "[data-testid='uc-deny-all-button']",
    },
    {
        "name": "CookieYes",
        "detect": ".cky-consent-container, [class*='cky-']",
        "accept": ".cky-btn-accept",
        "reject": ".cky-btn-reject, .cky-btn-customize",
    },
    {
        "name": "Quantcast",
        "detect": ".qc-cmp2-container, [class*='qc-cmp']",
        "accept": "[class*='qc-cmp2-summary-buttons'] button:first-child",
        "reject": "[class*='qc-cmp2-summary-buttons'] button:last-child",
    },
    {
        "name": "Borlabs",
        "detect": "#BorlabsCookieBox, [class*='BorlabsCookie']",
        "accept": "#BorlabsCookieBox .cookie-accept, [data-cookie-accept]",
        "reject": "#BorlabsCookieBox .cookie-refuse, [data-cookie-refuse]",
    },
    {
        "name": "Consentmanager",
        "detect": "#cmpbox, [class*='cmpbox']",
        "accept": ".cmpboxbtn.cmpboxbtnyes",
        "reject": ".cmpboxbtn.cmpboxbtnno",
    },
    {
        "name": "Klaro",
        "detect": ".klaro, [class*='klaro']",
        "accept": ".klaro .cm-btn-accept",
        "reject": ".klaro .cm-btn-decline",
    },
    {
        "name": "TarteAuCitron",
        "detect": "#tarteaucitronRoot, [class*='tarteaucitron']",
        "accept": "#tarteaucitronPersonalize2",
        "reject": "#tarteaucitronAllDenied2",
    },
]

# Generic fallback patterns (text-based)
GENERIC_ACCEPT_TEXTS = [
    "Alle akzeptieren", "Alles akzeptieren", "Alle Cookies akzeptieren",
    "Accept all", "Accept All Cookies", "Akzeptieren", "Zustimmen",
    "Einverstanden", "Ich stimme zu", "Ja, einverstanden",
]

GENERIC_REJECT_TEXTS = [
    "Nur notwendige", "Nur essentielle", "Ablehnen", "Alle ablehnen",
    "Reject", "Reject all", "Nur erforderliche", "Nur technisch notwendige",
    "Decline", "Nein", "Nicht einverstanden",
]


async def detect_banner(page: Page) -> BannerInfo:
    """Detect which CMP is used and return button selectors."""
    # Try CMP-specific selectors first
    for cmp in CMP_SELECTORS:
        try:
            count = await page.locator(cmp["detect"]).count()
            if count > 0:
                return BannerInfo(
                    detected=True,
                    provider=cmp["name"],
                    accept_selector=cmp["accept"],
                    reject_selector=cmp["reject"],
                )
        except Exception:
            continue

    # Generic fallback — search for buttons by text
    for text in GENERIC_ACCEPT_TEXTS:
        try:
            btn = page.get_by_text(text, exact=False)
            if await btn.count() > 0:
                accept = f'button:has-text("{text}")'
                # Try to find reject button nearby
                reject = ""
                for rtext in GENERIC_REJECT_TEXTS:
                    rbtn = page.get_by_text(rtext, exact=False)
                    if await rbtn.count() > 0:
                        reject = f'button:has-text("{rtext}")'
                        break
                return BannerInfo(
                    detected=True,
                    provider="Generic",
                    accept_selector=accept,
                    reject_selector=reject,
                )
        except Exception:
            continue

    return BannerInfo(detected=False, provider="", accept_selector="", reject_selector="")


async def click_button(page: Page, selector: str, timeout: int = 5000) -> bool:
    """Try to click a consent button. Returns True if clicked successfully."""
    if not selector:
        return False
    try:
        locator = page.locator(selector).first
        await locator.wait_for(state="visible", timeout=timeout)
        await locator.click()
        return True
    except Exception:
        return False
