#!/usr/bin/env python3
"""Tests for age encryption support."""
import os
import sys
import tempfile
import pytest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))

from e3po.editor import (
    Buffer, _is_age_file, _encrypt_to_age_file, _decrypt_age_file,
    AGE_AVAILABLE, PYRAGE_AVAILABLE
)


# Skip all tests if encryption is not available
pytestmark = pytest.mark.skipif(
    not AGE_AVAILABLE,
    reason="age encryption not available (install pyrage or age CLI)"
)


class TestAgeFileDetection:
    """Tests for _is_age_file function."""

    def test_detects_age_extension(self):
        """Files with .age extension are detected."""
        assert _is_age_file("secret.age") is True
        assert _is_age_file("/path/to/file.age") is True

    def test_non_age_extension(self):
        """Files without .age extension and no magic bytes."""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("plain text content")
            fname = f.name
        try:
            assert _is_age_file(fname) is False
        finally:
            os.unlink(fname)

    def test_detects_magic_bytes(self):
        """Files with age magic bytes are detected regardless of extension."""
        with tempfile.NamedTemporaryFile(mode='wb', suffix='.txt', delete=False) as f:
            # Write age header magic bytes
            f.write(b'age-encryption.org/v1\n')
            f.write(b'-> some recipient data\n')
            fname = f.name
        try:
            assert _is_age_file(fname) is True
        finally:
            os.unlink(fname)

    def test_nonexistent_file(self):
        """Non-existent files with .age extension are detected by extension."""
        assert _is_age_file("/nonexistent/file.age") is True
        assert _is_age_file("/nonexistent/file.txt") is False


class TestEncryptDecrypt:
    """Tests for encryption and decryption functions."""

    def test_encrypt_decrypt_roundtrip(self):
        """Content survives encrypt/decrypt roundtrip."""
        content = "This is secret content.\nWith multiple lines.\n"
        passphrase = "test-passphrase-123"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            # Encrypt
            result = _encrypt_to_age_file(content, fname, passphrase)
            assert result is True
            assert os.path.exists(fname)

            # Verify it's detected as age file
            assert _is_age_file(fname) is True

            # Decrypt
            decrypted = _decrypt_age_file(fname, passphrase)
            assert decrypted == content
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_wrong_passphrase_fails(self):
        """Decryption with wrong passphrase returns None."""
        content = "Secret content"
        passphrase = "correct-password"
        wrong_passphrase = "wrong-password"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            _encrypt_to_age_file(content, fname, passphrase)
            result = _decrypt_age_file(fname, wrong_passphrase)
            assert result is None
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_empty_content(self):
        """Empty content can be encrypted and decrypted."""
        content = ""
        passphrase = "test-pass"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            result = _encrypt_to_age_file(content, fname, passphrase)
            assert result is True

            decrypted = _decrypt_age_file(fname, passphrase)
            assert decrypted == content
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_unicode_content(self):
        """Unicode content is preserved through encryption."""
        content = "Unicode: 你好世界 🔐 émojis café"
        passphrase = "unicode-test"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            _encrypt_to_age_file(content, fname, passphrase)
            decrypted = _decrypt_age_file(fname, passphrase)
            assert decrypted == content
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_large_content(self):
        """Large content is handled correctly."""
        content = "Line of text\n" * 10000  # ~130KB
        passphrase = "large-file-test"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            result = _encrypt_to_age_file(content, fname, passphrase)
            assert result is True

            decrypted = _decrypt_age_file(fname, passphrase)
            assert decrypted == content
        finally:
            if os.path.exists(fname):
                os.unlink(fname)


class TestBufferEncryption:
    """Tests for Buffer encryption state."""

    def test_buffer_load_encrypted_file(self):
        """Buffer loads encrypted file with passphrase."""
        content = "Secret buffer content"
        passphrase = "buffer-test"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            _encrypt_to_age_file(content, fname, passphrase)

            buf = Buffer()
            result = buf.load(fname, passphrase)
            assert result is True
            assert buf.encrypted is True
            assert buf.passphrase == passphrase
            assert buf.lines == [content]
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_buffer_load_encrypted_without_passphrase_fails(self):
        """Buffer fails to load encrypted file without passphrase."""
        content = "Secret content"
        passphrase = "test-pass"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            _encrypt_to_age_file(content, fname, passphrase)

            buf = Buffer()
            result = buf.load(fname)  # No passphrase
            assert result is False
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_buffer_save_encrypted(self):
        """Buffer saves encrypted content."""
        content = "Original content"
        new_content = "Modified content"
        passphrase = "save-test"

        with tempfile.NamedTemporaryFile(suffix='.age', delete=False) as f:
            fname = f.name

        try:
            # Create encrypted file
            _encrypt_to_age_file(content, fname, passphrase)

            # Load, modify, save
            buf = Buffer()
            buf.load(fname, passphrase)
            buf.lines = [new_content]
            result = buf.save()
            assert result is True

            # Verify by loading again
            buf2 = Buffer()
            buf2.load(fname, passphrase)
            assert buf2.lines == [new_content]
        finally:
            if os.path.exists(fname):
                os.unlink(fname)

    def test_buffer_plaintext_not_encrypted(self):
        """Buffer loading plaintext file is not marked encrypted."""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("Plain text")
            fname = f.name

        try:
            buf = Buffer()
            result = buf.load(fname)
            assert result is True
            assert buf.encrypted is False
            assert buf.passphrase is None
        finally:
            os.unlink(fname)

    def test_clear_passphrase(self):
        """Passphrase is cleared from buffer."""
        buf = Buffer()
        buf.passphrase = "secret"
        buf.clear_passphrase()
        assert buf.passphrase is None


class TestCommittedEncryptedFile:
    """Tests using the committed encrypted test file."""

    def test_load_committed_encrypted_file(self):
        """Load the committed encrypted test file with known passphrase."""
        test_file = os.path.join(os.path.dirname(__file__), 'data', 'encrypted_test.age')
        if not os.path.exists(test_file):
            pytest.skip("Encrypted test file not found")

        buf = Buffer()
        result = buf.load(test_file, 'test123')
        assert result is True
        assert buf.encrypted is True
        assert 'This is an encrypted test file' in buf.lines[0]

    def test_committed_file_wrong_passphrase(self):
        """Committed encrypted file fails with wrong passphrase."""
        test_file = os.path.join(os.path.dirname(__file__), 'data', 'encrypted_test.age')
        if not os.path.exists(test_file):
            pytest.skip("Encrypted test file not found")

        buf = Buffer()
        result = buf.load(test_file, 'wrongpassword')
        assert result is False
