"""Tresorit storage plugin — adapter that satisfies the StorageProvider protocol.

Part of the local-first backup system (Mercury Wave 3). Uploads encrypted backups
to the user's own Tresorit account. User data never lives on Vastian servers.

Tresorit is the zero-knowledge encrypted option — end-to-end encryption at the
provider level (in addition to Vastian's own AES-256 encryption via pyzipper).
This means even Tresorit cannot read the backup contents. Ideal for privacy-first
users who want the strongest possible data protection.

Setup: Run `vastian setup tresorit` to configure API access and store credentials
in config/local/tresorit_token.json.

Requires: tresorit SDK or WebDAV access (optional dep). Tresorit supports WebDAV
for third-party app integrations, which is the recommended integration path.
"""

from __future__ import annotations

import json
import logging
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)

_TOKEN_FILE = "tresorit_token.json"
_VASTIAN_FOLDER = "Vastian Backups"


class TresoritAdapter:
    """Adapter that satisfies the StorageProvider protocol for Tresorit.

    Uses Tresorit's WebDAV interface for file operations. All files are
    end-to-end encrypted by Tresorit before leaving the user's device,
    providing zero-knowledge encryption on top of Vastian's own AES-256.

    Protocol satisfaction: isinstance(TresoritAdapter(...), StorageProvider) is True.
    """

    def __init__(self, config_dir: str | Path = "config/local") -> None:
        self._config_dir = Path(config_dir)
        self._token_path = self._config_dir / _TOKEN_FILE
        self._webdav_url: str | None = None
        self._session: Any = None

    def _ensure_session(self) -> None:
        """Lazily initialize the WebDAV session."""
        if self._session is not None:
            return
        if not self.is_authenticated():
            raise RuntimeError(
                "Tresorit not authenticated. Run `vastian setup tresorit` "
                "to configure WebDAV access credentials."
            )
        try:
            import requests

            token_data = json.loads(self._token_path.read_text(encoding="utf-8"))
            self._webdav_url = token_data.get("webdav_url", "")
            self._session = requests.Session()
            self._session.auth = (
                token_data.get("username", ""),
                token_data.get("password", ""),
            )
        except ImportError as err:
            raise RuntimeError(
                "requests dependency not installed. Run: pip install requests"
            ) from err

    def _remote_url(self, remote_path: str) -> str:
        """Build full WebDAV URL for a remote path."""
        base = self._webdav_url or ""
        return f"{base.rstrip('/')}/{_VASTIAN_FOLDER}/{remote_path}"

    async def upload(self, local_path: str, remote_path: str) -> dict:
        """Upload a local file to Tresorit via WebDAV."""
        self._ensure_session()

        local = Path(local_path)
        if not local.exists():
            raise FileNotFoundError(f"Local file not found: {local_path}")

        # Ensure the Vastian Backups folder exists
        folder_url = f"{self._webdav_url.rstrip('/')}/{_VASTIAN_FOLDER}/"
        self._session.request("MKCOL", folder_url)

        url = self._remote_url(remote_path)
        with open(local, "rb") as f:
            response = self._session.put(url, data=f)
            response.raise_for_status()

        return {
            "remote_path": remote_path,
            "remote_id": url,
            "size": local.stat().st_size,
            "timestamp": datetime.now(UTC).isoformat(),
        }

    async def download(self, remote_path: str, local_path: str) -> dict:
        """Download a file from Tresorit via WebDAV."""
        self._ensure_session()

        url = self._remote_url(remote_path)
        response = self._session.get(url)
        response.raise_for_status()

        local = Path(local_path)
        local.parent.mkdir(parents=True, exist_ok=True)
        local.write_bytes(response.content)

        return {
            "local_path": str(local),
            "size": local.stat().st_size,
            "timestamp": datetime.now(UTC).isoformat(),
        }

    async def list_files(self, prefix: str = "") -> list[dict]:
        """List files in the Vastian Backups folder on Tresorit via WebDAV PROPFIND."""
        self._ensure_session()

        folder_url = f"{self._webdav_url.rstrip('/')}/{_VASTIAN_FOLDER}/"
        response = self._session.request(
            "PROPFIND",
            folder_url,
            headers={"Depth": "1"},
        )

        if response.status_code != 207:
            return []

        # Parse WebDAV multistatus XML response
        files = []
        try:
            import xml.etree.ElementTree as ET

            root = ET.fromstring(response.text)
            ns = {"d": "DAV:"}
            for resp_elem in root.findall("d:response", ns):
                href = resp_elem.findtext("d:href", "", ns)
                if not href or href.endswith("/"):
                    continue
                name = href.rsplit("/", 1)[-1]
                if prefix and not name.startswith(prefix):
                    continue

                size_elem = resp_elem.find(".//d:getcontentlength", ns)
                modified_elem = resp_elem.find(".//d:getlastmodified", ns)

                files.append(
                    {
                        "remote_path": name,
                        "size": int(size_elem.text)
                        if size_elem is not None and size_elem.text
                        else 0,
                        "modified": modified_elem.text if modified_elem is not None else "",
                        "remote_id": href,
                    }
                )
        except Exception as e:
            logger.warning("Failed to parse WebDAV PROPFIND response: %s", e)

        return files

    async def delete(self, remote_path: str) -> bool:
        """Delete a file from Tresorit via WebDAV."""
        self._ensure_session()
        url = self._remote_url(remote_path)
        try:
            response = self._session.delete(url)
            return response.status_code in (200, 204)
        except Exception:
            return False

    def get_auth_url(self) -> str:
        """Get setup instructions for Tresorit WebDAV access."""
        return (
            "Tresorit uses zero-knowledge encryption and does not support "
            "standard OAuth2. To set up:\n"
            "1. Enable WebDAV access in your Tresorit account settings\n"
            "2. Generate an app-specific password for WebDAV\n"
            "3. Run `vastian setup tresorit` and enter your WebDAV credentials\n"
            "4. Credentials are stored in config/local/tresorit_token.json\n\n"
            "Your data is encrypted end-to-end by Tresorit — even Tresorit "
            "staff cannot read your backups. This is in addition to Vastian's "
            "own AES-256 encryption via pyzipper."
        )

    def is_authenticated(self) -> bool:
        """Check if valid Tresorit credentials exist."""
        if not self._token_path.exists():
            return False
        try:
            data = json.loads(self._token_path.read_text(encoding="utf-8"))
            return bool(data.get("webdav_url")) and bool(data.get("username"))
        except Exception:
            return False


def register() -> None:
    """Register the Tresorit storage plugin with the loader."""
    from vastian.loader import register as loader_register

    loader_register("tresorit_storage", TresoritAdapter)
