from __future__ import annotations

from argparse import Namespace
from typing import Any, Dict

from ..core.config import build_config
from ..core.runtime import SESSION_POOL, Runtime, _tenant_state_file
from ..core.browser import launch_browser_context
from ..core.artifacts import create_run_dir
from ..auth.session import ensure_logged_in
from ..auth.detect import is_mfa_screen, is_authenticated
from ..auth.mfa import handle_mfa


def _build_cfg(*, tenant_id: str, reuse_session: bool = True, keep_open: bool = True):
    args = Namespace(
        base_url=None,
        username=None,
        password=None,
        tenant_id=tenant_id,
        reuse_session=reuse_session,
        keep_open=keep_open,
        state_file=None,
        artifacts_dir=None,
        headless=None,
        slow_mo_ms=None,
        step=False,
        pause_on_mfa=False,
        mfa_code="",

        # Users
        user_email="",
        doc=[],
        file=[],
        comment=[],
        filter=[],

        # Timesheets
        timesheet_date="",
        timesheet_bu="",
        timesheet_user_id="",
        timesheet_user_name="",
        row=[],
        delete_all=False,
        include_protected=False,
    )
    return build_config(args)


def _register_runtime(tenant_id: str, rt: Runtime) -> None:
    with SESSION_POOL._lock:
        SESSION_POOL._sessions[tenant_id] = rt


def _create_pending_runtime(cfg, tenant_id: str) -> Runtime:
    SESSION_POOL._ensure_playwright()
    state_file = _tenant_state_file(cfg, tenant_id)
    storage_state_arg = str(state_file) if state_file.exists() else None

    browser, context = launch_browser_context(SESSION_POOL._pw, cfg, storage_state=storage_state_arg)
    page = context.new_page()

    rt = Runtime(
        tenant_id=tenant_id,
        browser=browser,
        context=context,
        page=page,
        state_file=state_file,
        managed=True,
        _pw=SESSION_POOL._pw,
    )
    rt.touch()
    return rt


def get_status(*, tenant_id: str) -> Dict[str, Any]:
    rt = SESSION_POOL._sessions.get(tenant_id)
    if not rt:
        return {"tenant_id": tenant_id, "state": "OFFLINE"}

    state = "ONLINE"
    try:
        if is_mfa_screen(rt.page):
            state = "MFA_REQUIRED"
        elif not is_authenticated(rt.page):
            state = "UNKNOWN"
    except Exception:
        state = "UNKNOWN"

    return {
        "tenant_id": tenant_id,
        "state": state,
        "state_file": str(rt.state_file),
        "last_active_ts": rt.last_active_ts,
    }


def connect_session(*, tenant_id: str) -> Dict[str, Any]:
    cfg = _build_cfg(tenant_id=tenant_id, reuse_session=True, keep_open=True)
    run_dir = create_run_dir(cfg, "ui-session")

    lock = SESSION_POOL.tenant_lock(tenant_id)
    with lock:
        existing = SESSION_POOL._sessions.get(tenant_id)
        if existing:
            return get_status(tenant_id=tenant_id)

        rt = _create_pending_runtime(cfg, tenant_id)
        try:
            ensure_logged_in(rt.page, cfg, run_dir=run_dir, mfa_code="", allow_mfa=False)
            # Logged in
            rt.save_state()
            rt.touch()
            _register_runtime(tenant_id, rt)
            return {"tenant_id": tenant_id, "state": "ONLINE"}
        except Exception:
            # Si estamos en MFA, dejamos la sesión viva
            if is_mfa_screen(rt.page):
                _register_runtime(tenant_id, rt)
                return {"tenant_id": tenant_id, "state": "MFA_REQUIRED"}
            # Error real: cerrar y propagar
            try:
                rt.close()
            except Exception:
                pass
            raise


def submit_mfa_code(*, tenant_id: str, code: str) -> Dict[str, Any]:
    rt = SESSION_POOL._sessions.get(tenant_id)
    if not rt:
        return {"tenant_id": tenant_id, "state": "OFFLINE", "message": "No active session"}

    if not is_mfa_screen(rt.page):
        return {"tenant_id": tenant_id, "state": "ONLINE", "message": "MFA not required"}

    cfg = _build_cfg(tenant_id=tenant_id, reuse_session=True, keep_open=True)
    run_dir = create_run_dir(cfg, "ui-session")
    handle_mfa(rt.page, cfg, run_dir=run_dir, mfa_code_arg=code)

    if is_authenticated(rt.page):
        rt.save_state()
        rt.touch()
        return {"tenant_id": tenant_id, "state": "ONLINE"}

    return {"tenant_id": tenant_id, "state": "MFA_REQUIRED", "message": "MFA rejected or not completed"}


def close_session(*, tenant_id: str) -> Dict[str, Any]:
    SESSION_POOL.close(tenant_id)
    return {"tenant_id": tenant_id, "state": "OFFLINE"}
