import subprocess
import tempfile
from pathlib import Path

from nebula_cert_manager.exceptions import CertManagerError


class SopsError(CertManagerError):
    pass


class Sops:
    def __init__(self, sops_bin: str = "sops", age_key: str | None = None):
        self.sops_bin = sops_bin
        self.age_key = age_key

    def decrypt(self, path: Path, config_path: Path | None = None) -> str:
        cmd = [self.sops_bin, "-d"]
        if config_path:
            cmd.extend(["--config", str(config_path)])
        cmd.append(str(path))
        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                check=True,
            )
        except subprocess.CalledProcessError as e:
            raise SopsError(f"sops decrypt failed: {e.stderr.strip()}") from e
        return result.stdout

    def encrypt_to_file(
        self, path: Path, plaintext: str, config_path: Path | None = None
    ) -> None:
        fd, tmp_path_str = tempfile.mkstemp(
            dir=path.parent, prefix=f".{path.name}.", suffix=".tmp"
        )
        tmp_path = Path(tmp_path_str)
        try:
            with open(fd, "w") as f:
                f.write(plaintext)
            cmd = [self.sops_bin, "-e", "-i"]
            if config_path:
                cmd.extend(["--config", str(config_path)])
            if self.age_key:
                cmd.extend(["--age", self.age_key])
            cmd.append(str(tmp_path))
            try:
                subprocess.run(
                    cmd,
                    capture_output=True,
                    text=True,
                    check=True,
                )
            except subprocess.CalledProcessError as e:
                raise SopsError(f"sops encrypt failed: {e.stderr.strip()}") from e
            tmp_path.rename(path)
        except BaseException:
            tmp_path.unlink(missing_ok=True)
            raise
