"""
Critical smoke tests for CLI commands.

These tests verify that CLI commands work end-to-end without
detailed mocking.
"""

import pytest
from pathlib import Path
from typer.testing import CliRunner
from kilit.cli import app
from kilit.crypto import generate_master_key

runner = CliRunner()


class TestInitCommand:
    """Test init command creates necessary files."""

    def test_init_creates_files(self, tmp_path, monkeypatch):
        """Init command creates encrypted file and master key."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"

        result = runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        assert result.exit_code == 0
        assert Path(creds_path).exists()
        assert Path(key_path).exists()
        assert "Initialized encrypted credentials" in result.stdout

    def test_init_with_existing_file_fails(self, tmp_path, monkeypatch):
        """Init with existing file fails without --force."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"

        # Create file first
        Path(creds_path).write_text("existing")

        result = runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        assert result.exit_code == 1
        assert "already exists" in result.stdout or "already exists" in result.output

    def test_init_with_force_overwrites(self, tmp_path, monkeypatch):
        """Init with --force overwrites existing file."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"

        # Create file first
        Path(creds_path).write_text("existing")

        result = runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
                "--force",
            ],
        )

        assert result.exit_code == 0
        assert "Initialized encrypted credentials" in result.stdout


class TestShowCommand:
    """Test show command displays credentials."""

    def test_show_displays_credentials(self, tmp_path, monkeypatch):
        """Show command displays decrypted credentials."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"

        # Initialize first
        runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        # Show credentials
        result = runner.invoke(
            app,
            [
                "show",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        assert result.exit_code == 0
        # Should show empty JSON object
        assert "{" in result.stdout

    def test_show_with_redact(self, tmp_path, monkeypatch):
        """Show with --redact hides values."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"

        # Initialize first
        runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        # Show with redact
        result = runner.invoke(
            app,
            [
                "show",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
                "--redact",
            ],
        )

        assert result.exit_code == 0
        # Empty object has no values to redact, but command should work
        assert "{" in result.stdout

    def test_show_with_wrong_key_fails(self, tmp_path, monkeypatch):
        """Show with wrong master key fails."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"
        wrong_key_path = "wrong_master.key"

        # Initialize with one key
        runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        # Create different key
        Path(wrong_key_path).write_text(generate_master_key())

        # Try to show with wrong key
        result = runner.invoke(
            app,
            [
                "show",
                "--path",
                creds_path,
                "--master-key-path",
                wrong_key_path,
            ],
        )

        assert result.exit_code == 1
        assert "Master Key Error" in result.stdout or "wrong master key" in result.stdout or "Master Key Error" in result.output or "wrong master key" in result.output


class TestExportCommand:
    """Test export command flattens credentials."""

    def test_export_outputs_env_vars(self, tmp_path, monkeypatch):
        """Export command outputs KEY=value format."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        key_path = "test_master.key"

        # Initialize first
        runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        # Export credentials
        result = runner.invoke(
            app,
            [
                "export",
                "--path",
                creds_path,
                "--master-key-path",
                key_path,
            ],
        )

        assert result.exit_code == 0
        # Empty object produces no output, but command should work


class TestRotateCommand:
    """Test rotate command re-encrypts with new key."""

    def test_rotate_generates_new_key(self, tmp_path, monkeypatch):
        """Rotate command generates new master key."""
        monkeypatch.chdir(tmp_path)

        creds_path = "test_creds.json.enc"
        old_key_path = "old_master.key"
        new_key_path = "new_master.key"

        # Initialize with old key
        runner.invoke(
            app,
            [
                "init",
                "--path",
                creds_path,
                "--master-key-path",
                old_key_path,
            ],
        )

        old_key = Path(old_key_path).read_text()

        # Rotate to new key
        result = runner.invoke(
            app,
            [
                "rotate",
                "--path",
                creds_path,
                "--master-key-path",
                old_key_path,
                "--write-new-master-key",
                new_key_path,
            ],
        )

        assert result.exit_code == 0
        assert "Master key rotated" in result.stdout
        assert Path(new_key_path).exists()

        new_key = Path(new_key_path).read_text()
        assert new_key != old_key

        # Verify can decrypt with new key
        result = runner.invoke(
            app,
            [
                "show",
                "--path",
                creds_path,
                "--master-key-path",
                new_key_path,
            ],
        )

        assert result.exit_code == 0
