"""Abre un vault en la app de escritorio Obsidian via el esquema obsidian://.

Construye el URI `obsidian://open?vault=<name>` y lanza la app para abrir ese vault.
Opcionalmente lo registra antes en la config de la app si recibe una ruta existente
no registrada (compone register_obsidian_vault del grupo obsidian).

Funcion impura: puede escribir la config de la app (al registrar) y lanza un proceso
externo (xdg-open) de forma desacoplada para abrir el URI en Obsidian.
"""

import os
import subprocess
import urllib.parse

from obsidian import register_obsidian_vault


def open_obsidian_vault(
    vault: str,
    register_if_missing: bool = True,
    launch: bool = True,
    config_path: str = "",
) -> dict:
    """Abre un vault en la app Obsidian construyendo y lanzando un URI obsidian://.

    Args:
        vault: ruta absoluta a un vault o su nombre (basename). Si es una ruta
            existente, el nombre del URI es su basename; si no parece una ruta
            existente se trata como nombre tal cual.
        register_if_missing: si True (default) y vault es una ruta existente no
            registrada en la app, la registra (open=True) antes de abrir.
        launch: si True (default) lanza la app via `xdg-open <uri>` desacoplado.
            Si False (util en tests) NO lanza nada, solo construye el URI.
        config_path: ruta al obsidian.json de la app. Vacio -> default
            ~/.config/obsidian/obsidian.json. Se pasa a register_obsidian_vault.

    Returns:
        dict con:
          - vault: el argumento original recibido.
          - uri: el URI obsidian://open?vault=<name> construido.
          - name: nombre del vault usado en el URI (basename o el propio vault).
          - launched: True si se lanzo xdg-open.
          - registered_now: True si se registro el vault en esta llamada.

    Raises:
        OSError: si el lanzamiento del proceso o el registro fallan por I/O.
    """
    registered_now = False
    is_path = os.path.sep in vault or vault.startswith("~")
    abs_path = os.path.abspath(os.path.expanduser(vault)) if is_path else ""

    # Si es una ruta existente, opcionalmente registrarla y usar su basename.
    if abs_path and os.path.isdir(abs_path):
        name = os.path.basename(abs_path.rstrip(os.path.sep))
        if register_if_missing:
            res = register_obsidian_vault(abs_path, open=True, config_path=config_path)
            registered_now = bool(res.get("registered"))
    elif is_path:
        # Parece ruta pero no existe: usar su basename como nombre.
        name = os.path.basename(abs_path.rstrip(os.path.sep))
    else:
        # Es un nombre, no una ruta.
        name = vault

    uri = "obsidian://open?vault=" + urllib.parse.quote(name)

    launched = False
    if launch:
        env = dict(os.environ)
        subprocess.Popen(
            ["xdg-open", uri],
            stdin=subprocess.DEVNULL,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            start_new_session=True,
            env=env,
        )
        launched = True

    return {
        "vault": vault,
        "uri": uri,
        "name": name,
        "launched": launched,
        "registered_now": registered_now,
    }


if __name__ == "__main__":
    import tempfile

    tmp = tempfile.mkdtemp()
    cfg = os.path.join(tmp, "obsidian.json")
    vault = os.path.join(tmp, "Mi Vault")
    os.makedirs(vault, exist_ok=True)

    r = open_obsidian_vault(vault, launch=False, config_path=cfg)
    assert r["launched"] is False, r
    assert r["registered_now"] is True, r
    assert r["name"] == "Mi Vault", r
    assert r["uri"] == "obsidian://open?vault=Mi%20Vault", r

    # Por nombre, sin lanzar ni registrar.
    r2 = open_obsidian_vault("MiVaultPorNombre", launch=False, config_path=cfg)
    assert r2["uri"] == "obsidian://open?vault=MiVaultPorNombre", r2
    assert r2["registered_now"] is False, r2
    print("open_obsidian_vault smoke OK")
