"""Ed25519 authentication for Botcoin Protocol."""
import base64
import json
import os
import time
from pathlib import Path

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

CREDENTIALS_PATH = Path.home() / ".botcoin" / "agent.json"


class BotcoinAuth:
    """Handles Ed25519 keypair management and request signing."""

    def __init__(self, agent_id: str, private_key_hex: str, public_key_hex: str = ""):
        self.agent_id = agent_id
        self.private_key_hex = private_key_hex
        self.public_key_hex = public_key_hex
        self._private_key = Ed25519PrivateKey.from_private_bytes(bytes.fromhex(private_key_hex))
        # Derive public key if not provided
        if not self.public_key_hex:
            self.public_key_hex = self._private_key.public_key().public_bytes_raw().hex()

    @classmethod
    def generate(cls) -> tuple[str, str]:
        """Generate a new Ed25519 keypair. Returns (private_hex, public_hex)."""
        private_key = Ed25519PrivateKey.generate()
        private_hex = private_key.private_bytes_raw().hex()
        public_hex = private_key.public_key().public_bytes_raw().hex()
        return private_hex, public_hex

    @classmethod
    def load(cls, path: Path = CREDENTIALS_PATH) -> "BotcoinAuth":
        """Load credentials from disk."""
        with open(path) as f:
            creds = json.load(f)
        return cls(
            agent_id=creds["agent_id"],
            private_key_hex=creds["private_key"],
            public_key_hex=creds.get("public_key", ""),
        )

    def save(self, path: Path = CREDENTIALS_PATH, name: str = ""):
        """Save credentials to disk."""
        path.parent.mkdir(parents=True, exist_ok=True)
        data = {
            "agent_id": self.agent_id,
            "private_key": self.private_key_hex,
            "public_key": self.public_key_hex,
        }
        if name:
            data["name"] = name
        with open(path, "w") as f:
            json.dump(data, f, indent=2)
        os.chmod(path, 0o600)

    def sign(self, body: str) -> tuple[str, str]:
        """Sign a request body. Returns (signature_b64, timestamp)."""
        ts = str(int(time.time()))
        message = f"{ts}.{body}"
        sig = self._private_key.sign(message.encode())
        return base64.b64encode(sig).decode(), ts

    def headers(self, body: str) -> dict:
        """Get auth headers for a request."""
        sig, ts = self.sign(body)
        return {
            "Content-Type": "application/json",
            "X-Agent-Id": self.agent_id,
            "X-Signature": sig,
            "X-Timestamp": ts,
        }
