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

from dataclasses import dataclass
from pathlib import Path
from typing import Optional, Tuple

from playwright.sync_api import Page

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


@dataclass(frozen=True)
class TargetDate:
    year: int
    month: int
    day: int

    @staticmethod
    def parse(iso_date: str) -> "TargetDate":
        """
        iso_date: 'YYYY-MM-DD'
        """
        y, m, d = iso_date.strip().split("-")
        return TargetDate(year=int(y), month=int(m), day=int(d))


def _wait_timesheet_ready(page: Page) -> None:
    page.wait_for_function(
        """() => {
            const u = location.href.toLowerCase();
            if (!u.includes('timesheet')) return false;
            const t = document.body && (document.body.innerText || '');
            return t.includes('Daily Timesheet') || t.includes('Timesheet for');
        }""",
        timeout=45_000,
    )


def _get_current_date_from_dom(page: Page) -> Optional[str]:
    """
    Usa el botón GPS que trae data-current-date="YYYY/MM/DD".
    Ej: data-current-date="2026/01/07"
    """
    try:
        btn = page.locator("button.gpsWindowFullBtn[data-current-date]").first
        if btn.count() == 0:
            return None
        v = btn.get_attribute("data-current-date")
        return v or None
    except Exception:
        return None


def _normalize_dom_date_to_iso(dom_date: str) -> str:
    """
    'YYYY/MM/DD' -> 'YYYY-MM-DD'
    """
    parts = dom_date.strip().split("/")
    if len(parts) != 3:
        return dom_date
    return f"{parts[0]}-{parts[1]}-{parts[2]}"


def _wait_date_changed(page: Page, target_iso: str) -> None:
    """
    Espera que el DOM refleje la fecha objetivo (si está disponible).
    Si no está, al menos espera navegación/settle.
    """
    # Primero intenta por data-current-date (lo más robusto)
    page.wait_for_function(
        """(targetIso) => {
            const btn = document.querySelector("button.gpsWindowFullBtn[data-current-date]");
            if (!btn) return false;
            const v = btn.getAttribute("data-current-date") || "";
            // v es YYYY/MM/DD
            const iso = v.replaceAll("/", "-");
            return iso === targetIso;
        }""",
        arg=target_iso,
        timeout=20_000,
    )


def run(page: Page, cfg, run_dir: Path, *, target_date: str) -> None:
    """
    Cambia la fecha del Timesheet usando el calendario de AroFlo (a.calDay),
    seleccionando el link cuyo href contiene:
      sday=<D>&smonth=<M>&syear=<Y>

    target_date: 'YYYY-MM-DD' (ej '2026-01-08')
    """
    _wait_timesheet_ready(page)

    tgt = TargetDate.parse(target_date)
    target_iso = f"{tgt.year:04d}-{tgt.month:02d}-{tgt.day:02d}"

    # Si ya estamos en esa fecha, no hacemos nada.
    dom_date = _get_current_date_from_dom(page)
    if dom_date:
        cur_iso = _normalize_dom_date_to_iso(dom_date)
        if cur_iso == target_iso:
            log_step(f"ts-date-already-{target_iso}", page)
            return

    shot(page, run_dir, f"ts-date-01-before-{target_iso}")
    log_step(f"ts-date-01-before-{target_iso}", page)
    pause(cfg, f"Before selecting date {target_iso}")

    # Selector robusto: link calDay cuyo href tenga sday/smonth/syear
    # Ojo: sday y smonth parecen ir sin cero a la izquierda (8, 1).
    href_fragment = f"sday={tgt.day}&smonth={tgt.month}&syear={tgt.year}"

    # Restringimos al calendario dentro de .af-datepicker para evitar falsos positivos.
    cal_link = page.locator(".af-datepicker a.calDay").filter(
        has=page.locator(f"a.calDay[href*='{href_fragment}']")
    )
    # El filter anterior puede ser overkill; hacemos fallback directo.
    if cal_link.count() == 0:
        cal_link = page.locator(f".af-datepicker a.calDay[href*='{href_fragment}']").first
    else:
        cal_link = cal_link.first

    if cal_link.count() == 0:
        shot(page, run_dir, f"ts-date-99-not-found-{target_iso}")
        raise RuntimeError(f"No encontré link del calendario para {target_iso} (href*='{href_fragment}').")

    # Click + esperar que cargue la fecha
    cal_link.click()

    # Esperar que la fecha cambie (data-current-date debe actualizar)
    _wait_date_changed(page, target_iso)

    # Esperar que el timesheet esté "ready" nuevamente
    _wait_timesheet_ready(page)

    shot(page, run_dir, f"ts-date-02-after-{target_iso}")
    log_step(f"ts-date-02-after-{target_iso}", page)
    pause(cfg, f"After selecting date {target_iso}")
