# apps/aroflo_connector_app/ui_automation/flows/timesheet_select_bu.py
from __future__ import annotations

from pathlib import Path
from typing import Optional

from playwright.sync_api import Page

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


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:
    """
    En tu HTML aparece:
      Tawk_API.setAttributes({"currentbu":"Utility Solutions Group", ...})
    Entonces podemos esperar a que exista "currentbu":"Telecommunications" en scripts/body.
    Es menos elegante, pero sirve como señal cuando el header dropdown no está.
    """
    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)

    # Espera a que el UL del selector esté visible (evita clicks antes de render)
    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:
    # En tu HTML: <ul data-bu-selector> ... <a href="/ims/Site/Home/index.cfm?view=1&hhsCoded=...&tid=IMS.HME">Telecommunications</a>
    # Lo correcto es click al <a>, no al <li>.
    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:
        # fallback menos estricto
        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 ""
    # Si hay href, podemos esperar por URL (aunque sea same-document).
    # Nota: puede ser relativo. Playwright acepta regex.
    href_escaped = re.escape(href)

    # Click + espera flexible:
    a.click(timeout=8_000, force=True)

    # 1) Si cambia URL, perfecto (a veces cambia y a veces no, depende de cómo AroFlo maneje esto)
    try:
        if href:
            page.wait_for_url(re.compile(href_escaped), timeout=15_000)
    except Exception:
        pass

    # 2) Siempre espera a que el header refleje el BU (tu confirmación “real”)
    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:
    """
    HTML real:
      <td> <a href="/ims/Site/Home/index.cfm?view=1&hhsJID=...">Telecommunications</a>
    """
    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=']).")

    # Ese click sí suele navegar
    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) -> None:
    target_bu = (target_bu or "").strip()
    if not target_bu:
        return

    _wait_ims_ready(page)

    # Si hay header, y ya está, salir.
    if _header_bu_exists(page):
        cur = _get_current_bu_from_header(page)
        if cur and cur.strip() == target_bu:
            log_step(f"ts-bu-already-{target_bu}", page)
            return

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

    # 1) Si existe dropdown, úsalo
    if _header_bu_exists(page):
        log_step(f"ts-bu-mode-dropdown-{target_bu}", page)
        _open_bu_menu(page)
        _wait_menu_has_target(page, target_bu)

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

        _click_target_bu_dropdown(page, target_bu)

        # Confirmar aplicado por header
        _wait_bu_applied_header(page, target_bu)

    else:
        # 2) Si NO existe dropdown, usa la tabla del dashboard
        log_step(f"ts-bu-mode-dashboard-table-{target_bu}", page)
        _click_bu_from_dashboard_table(page, target_bu)

        # Después del cambio, a veces aparece el header en la nueva vista; si aparece, úsalo.
        if _header_bu_exists(page):
            _wait_bu_applied_header(page, target_bu)
        else:
            # Si sigue sin existir, valida por la señal Tawk currentbu
            _wait_bu_applied_by_tawk(page, target_bu)

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