import os
import stat
from pathlib import Path

import pytest

from backend.app.services.credential_crypto import (
    CredentialCrypto,
    InvalidCredentialBlob,
)

pytestmark = pytest.mark.integration


def test_load_or_create_writes_key_with_mode_0600(tmp_path):
    key_path = tmp_path / "secrets" / "credential_key.b64"
    CredentialCrypto(key_path, bootstrap_ok=True)
    assert key_path.exists()
    mode = stat.S_IMODE(os.stat(key_path).st_mode)
    assert mode == 0o600
    # parent dir is 0o700
    parent_mode = stat.S_IMODE(os.stat(key_path.parent).st_mode)
    assert parent_mode == 0o700


def test_load_existing_key_is_idempotent(tmp_path):
    key_path = tmp_path / "credential_key.b64"
    crypto1 = CredentialCrypto(key_path, bootstrap_ok=True)
    contents_after_first = key_path.read_bytes()
    crypto2 = CredentialCrypto(key_path, bootstrap_ok=True)
    contents_after_second = key_path.read_bytes()
    assert contents_after_first == contents_after_second
    # And both crypto instances decrypt each other's ciphertext
    ct = crypto1.encrypt("hello")
    assert crypto2.decrypt(ct) == "hello"


def test_encrypt_decrypt_round_trip(tmp_path):
    crypto = CredentialCrypto(tmp_path / "k", bootstrap_ok=True)
    plaintext = "domain.com\tTRUE\t/\tTRUE\t1700000000\tname\tvalue"
    ct = crypto.encrypt(plaintext)
    assert isinstance(ct, bytes)
    assert ct != plaintext.encode()
    assert crypto.decrypt(ct) == plaintext


def test_decrypt_with_wrong_key_raises(tmp_path):
    crypto_a = CredentialCrypto(tmp_path / "a", bootstrap_ok=True)
    crypto_b = CredentialCrypto(tmp_path / "b", bootstrap_ok=True)
    ct = crypto_a.encrypt("secret")
    with pytest.raises(InvalidCredentialBlob):
        crypto_b.decrypt(ct)


def test_missing_key_without_bootstrap_raises(tmp_path, monkeypatch):
    """Audit 2026-06-02: without explicit opt-in, a missing key file
    is a fatal startup error — silent regeneration on partial restore
    would make every existing Credential row undecryptable."""
    from backend.app.services.credential_crypto import MissingCredentialKey
    monkeypatch.delenv("CURATOR_BOOTSTRAP_NEW_KEY", raising=False)
    with pytest.raises(MissingCredentialKey):
        CredentialCrypto(tmp_path / "absent.b64")


def test_missing_key_with_env_var_bootstraps(tmp_path, monkeypatch):
    """The env var CURATOR_BOOTSTRAP_NEW_KEY=1 is the operator's
    first-time-setup opt-in for auto-creating the key file."""
    monkeypatch.setenv("CURATOR_BOOTSTRAP_NEW_KEY", "1")
    key_path = tmp_path / "bootstrap.b64"
    CredentialCrypto(key_path)  # no bootstrap_ok kwarg — relies on env
    assert key_path.exists()
