"""CloudBackup: optional encrypted cloud backup to S3/GCS."""

import json
import hashlib
import base64
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

from memotrail.utils import get_logger

logger = get_logger("memotrail.sync.cloud")


class CloudBackup:
    """Optional encrypted backup to S3-compatible storage.

    Requires: pip install memotrail[sync]  (boto3)
    """

    def __init__(
        self,
        bucket: str,
        prefix: str = "memotrail-backup",
        encryption_key: Optional[str] = None,
        endpoint_url: Optional[str] = None,
    ):
        self.bucket = bucket
        self.prefix = prefix
        self.encryption_key = encryption_key
        self.endpoint_url = endpoint_url
        self._client = None

    @property
    def client(self):
        """Lazy-init S3 client."""
        if self._client is None:
            try:
                import boto3
            except ImportError:
                raise ImportError(
                    "Cloud backup requires boto3. Install with: pip install memotrail[sync]"
                )
            kwargs = {}
            if self.endpoint_url:
                kwargs["endpoint_url"] = self.endpoint_url
            self._client = boto3.client("s3", **kwargs)
        return self._client

    def backup(self, export_path: str | Path) -> str:
        """Upload an export file to S3.

        If encryption_key is set, encrypts the content before upload.

        Args:
            export_path: Path to the JSON export file

        Returns:
            S3 key of the uploaded file
        """
        export_path = Path(export_path)
        content = export_path.read_bytes()

        if self.encryption_key:
            content = self._encrypt(content)

        timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
        s3_key = f"{self.prefix}/{timestamp}_{export_path.name}"

        self.client.put_object(
            Bucket=self.bucket,
            Key=s3_key,
            Body=content,
            ContentType="application/json",
        )

        logger.info(f"Uploaded backup to s3://{self.bucket}/{s3_key}")
        return s3_key

    def restore(self, s3_key: str, output_path: str | Path) -> Path:
        """Download a backup from S3.

        If encryption_key is set, decrypts the content after download.

        Args:
            s3_key: S3 key of the backup file
            output_path: Path to save the downloaded file

        Returns:
            Path to the downloaded file
        """
        output_path = Path(output_path)

        response = self.client.get_object(Bucket=self.bucket, Key=s3_key)
        content = response["Body"].read()

        if self.encryption_key:
            content = self._decrypt(content)

        output_path.write_bytes(content)
        logger.info(f"Restored backup from s3://{self.bucket}/{s3_key} to {output_path}")
        return output_path

    def list_backups(self) -> list[dict]:
        """List available backups in S3.

        Returns:
            List of backup metadata dicts
        """
        response = self.client.list_objects_v2(
            Bucket=self.bucket,
            Prefix=self.prefix + "/",
        )

        backups = []
        for obj in response.get("Contents", []):
            backups.append({
                "key": obj["Key"],
                "size": obj["Size"],
                "last_modified": obj["LastModified"].isoformat(),
            })

        return sorted(backups, key=lambda x: x["last_modified"], reverse=True)

    def _encrypt(self, data: bytes) -> bytes:
        """Simple XOR-based encryption for at-rest protection.

        Note: For production use, consider using a proper encryption library
        like cryptography.fernet.
        """
        key_bytes = hashlib.sha256(self.encryption_key.encode()).digest()
        encrypted = bytes(
            data[i] ^ key_bytes[i % len(key_bytes)] for i in range(len(data))
        )
        return base64.b64encode(encrypted)

    def _decrypt(self, data: bytes) -> bytes:
        """Decrypt XOR-encrypted data."""
        data = base64.b64decode(data)
        key_bytes = hashlib.sha256(self.encryption_key.encode()).digest()
        return bytes(
            data[i] ^ key_bytes[i % len(key_bytes)] for i in range(len(data))
        )
