from __future__ import annotations

import io
import logging

from muleline.storage.base import StorageBackend

log = logging.getLogger(__name__)


class WebDAVStorage(StorageBackend):
    """WebDAV storage backend (Nextcloud, ownCloud, generic WebDAV servers)."""

    def __init__(self, url: str, username: str, password: str, prefix: str = ""):
        self.prefix = prefix.strip("/")

        try:
            from webdav3.client import Client
        except ImportError:
            raise ImportError("Install webdavclient3 for WebDAV storage: pip install muleline[webdav]")

        self._client = Client({"webdav_hostname": url, "webdav_login": username, "webdav_password": password})

    def _key(self, key: str) -> str:
        if self.prefix:
            return f"{self.prefix}/{key}"
        return key

    def save(self, key: str, content: bytes, mime_type: str = "") -> bool:
        try:
            remote = self._key(key)
            parent = remote.rsplit("/", 1)[0] if "/" in remote else ""
            if parent:
                self._client.mkdir(parent)
            self._client.upload_to(io.BytesIO(content), remote)
            return True
        except Exception as e:
            log.error("WebDAV save failed for %s: %s", key, e)
            return False

    def read(self, key: str) -> bytes | None:
        try:
            buf = io.BytesIO()
            self._client.download_from(buf, self._key(key))
            return buf.getvalue()
        except Exception as e:
            log.error("WebDAV read failed for %s: %s", key, e)
            return None

    def delete(self, key: str) -> bool:
        try:
            self._client.clean(self._key(key))
            return True
        except Exception as e:
            log.error("WebDAV delete failed for %s: %s", key, e)
            return False

    def exists(self, key: str) -> bool:
        try:
            return self._client.check(self._key(key))
        except Exception:
            return False

    def url(self, key: str, expires: int = 3600) -> str | None:
        return None
