"""Utilities to select a Business Unit (BU) in AroFlo IMS via Playwright."""
# apps/aroflo_connector_app/ui_automation_zones/core/bu_select.py
from __future__ import annotations

import re
from pathlib import Path
from typing import Optional

from playwright.sync_api import Page

from .artifacts import shot
from .log import log_step, pause


def _wait_ims_ready(page: Page) -> None:
    page.wait_for_function("() => location.href.includes('/ims/')", timeout=30_000)


def _header_bu_exists(page: Page) -> bool:
    try:
        return page.locator("#imsBUNavigationBtn").count() > 0
    except Exception:
        return False


def _get_current_bu_from_header(page: Page) -> Optional[str]:
    try:
        el = page.locator("#imsBUNavigationBtn .af-truncate--text").first
        if el.count() == 0:
            return None
        t = el.inner_text().strip()
        return t or None
    except Exception:
        return None


def _wait_bu_applied_header(page: Page, target_bu: str, timeout_ms: int = 25_000) -> None:
    page.wait_for_function(
        """(target) => {
            const el = document.querySelector("#imsBUNavigationBtn .af-truncate--text");
            if (!el) return false;
            return (el.textContent || "").trim() === target;
        }""",
        arg=target_bu,
        timeout=timeout_ms,
    )


def _wait_bu_applied_by_tawk(page: Page, target_bu: str, timeout_ms: int = 25_000) -> None:
    """
    Señal alternativa:
      Tawk_API.setAttributes({"currentbu":"Utility Solutions Group", ...})
    Útil cuando no existe el header dropdown.
    """
    page.wait_for_function(
        """(target) => {
            const txt = document.documentElement ? (document.documentElement.innerHTML || "") : "";
            return txt.includes('"currentbu":"'+target+'"')
                || txt.includes("'currentbu':'"+target+"'")
                || txt.includes('currentbu":"'+target);
        }""",
        arg=target_bu,
        timeout=timeout_ms,
    )


# ---------- MODO A: dropdown ----------
def _open_bu_menu(page: Page) -> None:
    btn = page.locator("#imsBUNavigationBtn").first
    if btn.count() == 0:
        raise RuntimeError("No existe #imsBUNavigationBtn en esta vista.")
    btn.click(timeout=6_000, force=True)

    page.locator("ul[data-bu-selector]").first.wait_for(state="visible", timeout=10_000)


def _wait_menu_has_target(page: Page, target_bu: str) -> None:
    page.wait_for_function(
        """(target) => {
            const uls = Array.from(document.querySelectorAll("ul[data-bu-selector]"));
            for (const ul of uls) {
                const items = ul.querySelectorAll("li, a, button");
                if (!items || items.length === 0) continue;
                const hit = Array.from(items).some(el => (el.textContent || "").trim() === target);
                if (hit) return true;
            }
            const menuItems = Array.from(document.querySelectorAll("[role='menuitem'], [role='option']"));
            if (menuItems.length > 0) {
                return menuItems.some(el => (el.textContent || "").trim() === target);
            }
            return false;
        }""",
        arg=target_bu,
        timeout=25_000,
    )


def _click_target_bu_dropdown(page: Page, target_bu: str) -> None:
    a = (
        page.locator("ul[data-bu-selector] a")
        .filter(has_text=re.compile(rf"^\s*{re.escape(target_bu)}\s*$"))
        .first
    )
    if a.count() == 0:
        a = page.locator("ul[data-bu-selector] a").filter(has_text=target_bu).first

    if a.count() == 0:
        raise RuntimeError(f"No encontré el link (<a>) del BU '{target_bu}' en el menú dropdown.")

    href = a.get_attribute("href") or ""
    href_escaped = re.escape(href)

    a.click(timeout=8_000, force=True)

    # A veces cambia URL, a veces no. Si hay href, intentamos esperar.
    try:
        if href:
            page.wait_for_url(re.compile(href_escaped), timeout=15_000)
    except Exception:
        pass

    try:
        page.wait_for_load_state("domcontentloaded", timeout=15_000)
    except Exception:
        pass

    page.wait_for_timeout(400)


# ---------- MODO B: tabla dashboard ----------
def _click_bu_from_dashboard_table(page: Page, target_bu: str) -> None:
    link = page.locator("a[href*='hhsJID=']").filter(has_text=target_bu).first
    if link.count() == 0:
        raise RuntimeError(f"No encontré link de BU '{target_bu}' en la tabla (a[href*='hhsJID=']).")

    with page.expect_navigation(wait_until="domcontentloaded", timeout=20_000):
        link.click(timeout=8_000, force=True)

    try:
        page.wait_for_load_state("networkidle", timeout=20_000)
    except Exception:
        pass
    page.wait_for_timeout(400)


def run(page: Page, cfg, run_dir: Path, *, target_bu: str, tag_prefix: str = "bu") -> None:
    """
    Selector común (reusable por cualquier zona):
    - Si hay dropdown (#imsBUNavigationBtn): selecciona desde el menú.
    - Si no hay dropdown: usa link en tabla dashboard (hhsJID).
    - Valida aplicado por header; si no hay header, valida por señal de Tawk currentbu.

    tag_prefix: prefijo para screenshots/logs ("bu" por defecto)
    """
    target_bu = (target_bu or "").strip()
    if not target_bu:
        return

    _wait_ims_ready(page)

    if _header_bu_exists(page):
        cur = _get_current_bu_from_header(page)
        if cur and cur.strip() == target_bu:
            log_step(f"{tag_prefix}-already-{target_bu}", page)
            return

    shot(page, run_dir, f"{tag_prefix}-01-before-{target_bu}")
    log_step(f"{tag_prefix}-01-before-{target_bu}", page)
    pause(cfg, f"Before selecting BU: {target_bu}")

    if _header_bu_exists(page):
        log_step(f"{tag_prefix}-mode-dropdown-{target_bu}", page)
        _open_bu_menu(page)
        _wait_menu_has_target(page, target_bu)

        shot(page, run_dir, f"{tag_prefix}-02-menu-open-{target_bu}")
        log_step(f"{tag_prefix}-02-menu-open-{target_bu}", page)

        _click_target_bu_dropdown(page, target_bu)
        _wait_bu_applied_header(page, target_bu)
    else:
        log_step(f"{tag_prefix}-mode-dashboard-table-{target_bu}", page)
        _click_bu_from_dashboard_table(page, target_bu)

        if _header_bu_exists(page):
            _wait_bu_applied_header(page, target_bu)
        else:
            _wait_bu_applied_by_tawk(page, target_bu)

    shot(page, run_dir, f"{tag_prefix}-03-after-{target_bu}")
    log_step(f"{tag_prefix}-03-after-{target_bu}", page)
    pause(cfg, f"After selecting BU: {target_bu}")
