# /apps/aroflo_connector_app/ui_automation/commands/users_upload_documents.py
from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import List

from playwright.sync_api import sync_playwright

from ..core.artifacts import create_run_dir, shot
from ..core.browser import launch_browser_context
from ..core.log import log_step, pause
from ..auth.session import ensure_logged_in
from ..flows.users_nav import run as users_nav_flow_run
from ..flows.users_select_user import users_select_user_by_email
from ..flows.users_upload_documents import users_upload_documents


@dataclass(frozen=True)
class DocSpec:
    file: Path
    comment: str = ""
    filter: str = ""


_ALLOWED_FILTERS = {
    "Internal Only",
    "Internal Admin Only (Legacy)",
    "Internal Admin and Manager Only (Legacy)",
    "Show Client",
    "Show Contractor",
    "Show All",
}


def _parse_doc_spec(s: str) -> DocSpec:
    # "file=/a.pdf;comment=uno;filter=Internal Only"
    parts = [p.strip() for p in s.split(";") if p.strip()]
    kv = {}
    for part in parts:
        if "=" not in part:
            raise ValueError(f"Invalid --doc chunk (expected key=value): {part!r}")
        k, v = part.split("=", 1)
        kv[k.strip().lower()] = v.strip()

    if not kv.get("file"):
        raise ValueError(f"--doc missing required 'file=': {s!r}")

    f = Path(kv["file"]).expanduser().resolve()
    c = kv.get("comment", "")
    flt = kv.get("filter", "")

    if flt and flt not in _ALLOWED_FILTERS:
        raise ValueError(f"Invalid filter in --doc: {flt!r}. Allowed: {sorted(_ALLOWED_FILTERS)}")

    return DocSpec(file=f, comment=c, filter=flt)


def _build_docs(cfg) -> List[DocSpec]:
    # Preferir --doc si existe
    doc_specs = list(getattr(cfg, "user_docs", []) or [])
    if doc_specs:
        docs = [_parse_doc_spec(s) for s in doc_specs]
        return docs

    # Backward compatible: --file/--comment/--filter indexados
    files = list(getattr(cfg, "user_files", []) or [])
    if not files:
        raise SystemExit("Missing files. Use one or more --doc ... OR --file /path/to/doc.pdf")

    comments = list(getattr(cfg, "user_comments", []) or [])
    filters = list(getattr(cfg, "user_filters", []) or [])

    docs: List[DocSpec] = []
    for i, f in enumerate(files):
        fp = Path(f).expanduser().resolve()
        c = comments[i] if i < len(comments) else ""
        flt = filters[i] if i < len(filters) else ""
        if flt and flt not in _ALLOWED_FILTERS:
            raise SystemExit(f"Invalid --filter: {flt!r}. Allowed: {sorted(_ALLOWED_FILTERS)}")
        docs.append(DocSpec(file=fp, comment=c, filter=flt))

    return docs


def cmd_users_upload_documents(cfg, mfa_code: str = "") -> int:
    run_dir = create_run_dir(cfg, "users-upload-docs")

    if not getattr(cfg, "user_email", "").strip():
        raise SystemExit("Missing --user-email (required).")

    docs = _build_docs(cfg)
    for d in docs:
        if not d.file.exists():
            raise SystemExit(f"Upload file does not exist: {d.file}")

    with sync_playwright() as p:
        browser, context = launch_browser_context(p, cfg, storage_state=str(cfg.state_file))
        page = context.new_page()

        allow_mfa = bool(getattr(cfg, "pause_on_mfa", False))
        ensure_logged_in(page, cfg, run_dir, mfa_code=mfa_code, allow_mfa=allow_mfa)

        shot(page, run_dir, "users-upload-00-auth-ok")
        log_step("users-upload-00-auth-ok", page)
        pause(cfg, "Authenticated OK, starting Users navigation")

        # 1) navegar a Manage -> Users (listado)
        users_nav_flow_run(page, cfg, run_dir)

        # 2) seleccionar usuario por email
        email = cfg.user_email.strip()
        result = users_select_user_by_email(
            page,
            email=email,
            run_dir=run_dir,
            max_pages=30,
            timeout_ms=8000,
            screenshot_on_fail=True,
        )
        if not result.found:
            shot(page, run_dir, "users-upload-user-not-found")
            log_step("users-upload-user-not-found", page)
            raise RuntimeError(f"User not found by email: {email}")

        shot(page, run_dir, "users-upload-01-user-selected")
        log_step("users-upload-01-user-selected", page)
        pause(cfg, "User profile opened. Ready to upload documents")

        # 3) upload 1..N
        upload_results = users_upload_documents(
            page,
            docs=docs,          # <--- nuevo
            cfg=cfg,
            run_dir=run_dir,
            timeout_ms=45_000,
        )

        ok = [r for r in upload_results if r.ok]
        bad = [r for r in upload_results if not r.ok]

        print("UPLOAD SUMMARY")
        print("-------------")
        print(f"OK: {len(ok)}")
        for r in ok:
            print(f"  - {r.filename}")
        print(f"FAILED: {len(bad)}")
        for r in bad:
            print(f"  - {r.filename} :: {r.reason}")

        shot(page, run_dir, "users-upload-99-done")
        log_step("users-upload-99-done", page)

        try:
            context.storage_state(path=str(cfg.state_file))
        except Exception:
            pass

        try:
            context.close()
        except Exception:
            pass

        try:
            browser.close()
        except Exception:
            pass

    return 0 if len(bad) == 0 else 2
