"""Sube (PUT) un VCALENDAR a una coleccion CalDAV via HTTP Basic auth.

Funcion impura: hace una peticion HTTP PUT. Construye el header
`Authorization: Basic base64(user:pass)` a mano con stdlib. El nombre del
recurso se deriva del UID saneado (`safe(uid) + '.ics'`). Maneja errores sin
lanzar: devuelve {status: 'ok', http_status: int} en exito o
{status: 'error', error: str}. Solo usa stdlib (urllib, base64, re, ssl).
"""

import base64
import re
import ssl
import urllib.error
import urllib.request

_UNSAFE_RE = re.compile(r"[^A-Za-z0-9_.-]")


def _basic_auth_header(username: str, password: str) -> str:
    raw = ("%s:%s" % (username, password)).encode("utf-8")
    return "Basic " + base64.b64encode(raw).decode("ascii")


def _safe_resource_name(uid: str, ext: str) -> str:
    safe = _UNSAFE_RE.sub("_", uid)[:120]
    return safe + ext


def _join_url(base_url: str, collection_path: str, resource: str) -> str:
    return base_url.rstrip("/") + "/" + collection_path.strip("/") + "/" + resource


def caldav_put_event(
    base_url: str,
    username: str,
    password: str,
    collection_path: str,
    uid: str,
    vcalendar_text: str,
    *,
    timeout_s: float = 20.0,
    verify_tls: bool = True,
) -> dict:
    """Sube un VCALENDAR (con un VEVENT) a una coleccion CalDAV (PUT).

    Args:
        base_url: URL base del servidor DAV (p.ej. 'https://dav-x.example.com').
        username: usuario para HTTP Basic auth.
        password: contrasena para HTTP Basic auth.
        collection_path: ruta de la coleccion CalDAV (p.ej.
            '/enmanuel/calendars/calendar/').
        uid: UID del evento; se sanea para formar el nombre del recurso.
        vcalendar_text: texto completo del VCALENDAR (BEGIN:VCALENDAR..END).
        timeout_s: timeout de la peticion en segundos. Default 20.0.
        verify_tls: si True (default) verifica el certificado TLS. No desactivar
            salvo en entornos de prueba controlados.

    Returns:
        dict. En exito: {status: 'ok', http_status: int, url: str}. En error
        (sin lanzar): {status: 'error', error: str, http_status: int|None}.
    """
    resource = _safe_resource_name(uid, ".ics")
    url = _join_url(base_url, collection_path, resource)
    body = vcalendar_text
    if not body.endswith("\r\n"):
        body = body.rstrip("\r\n") + "\r\n"
    data = body.encode("utf-8")
    headers = {
        "Authorization": _basic_auth_header(username, password),
        "Content-Type": "text/calendar; charset=utf-8",
    }
    req = urllib.request.Request(url, data=data, method="PUT", headers=headers)

    context = None if verify_tls else ssl._create_unverified_context()
    try:
        with urllib.request.urlopen(req, timeout=timeout_s, context=context) as resp:
            return {"status": "ok", "http_status": resp.status, "url": url}
    except urllib.error.HTTPError as e:
        return {"status": "error", "error": "http %s" % e.code, "http_status": e.code}
    except urllib.error.URLError as e:
        return {"status": "error", "error": str(e.reason), "http_status": None}
    except Exception as e:  # noqa: BLE001
        return {"status": "error", "error": str(e), "http_status": None}
