"""Tests for complyform.cli.generate_cmd — generate command."""

from __future__ import annotations

import json
from typing import TYPE_CHECKING
from unittest.mock import patch

if TYPE_CHECKING:
    from pathlib import Path

import pytest
import yaml
from typer.testing import CliRunner

from complyform.cli.main import app
from complyform.core.greenfield.service_catalog import _reset_cache as _reset_catalog

runner = CliRunner()


@pytest.fixture(autouse=True)
def _clear_caches() -> None:
    _reset_catalog()


def _write_init_config(path: Path, **overrides: object) -> Path:
    """Write a minimal valid complyform.init.yaml."""
    data = {
        "version": "1",
        "project": {
            "cloud": "gcp",
            "project_id": "my-test-project",
            "region": "us-central1",
        },
        "compliance": {
            "frameworks": ["soc2"],
        },
        "services": [
            {
                "id": "gcs",
                "display_name": "Cloud Storage",
                "category": "object_storage",
            },
        ],
        "output": {
            "directory": str(overrides.get("output_directory", path.parent / "output")),
        },
        "metadata": {
            "generated_by": "complyform",
            "generated_at": "2026-01-01T00:00:00Z",
            "cli_version": "0.1.0",
            "tier": "community",
        },
    }
    path.write_text(yaml.dump(data), encoding="utf-8")
    return path


class TestGenerateHappyPath:
    @patch("complyform.core.greenfield.renderer._run_fmt")
    def test_produces_files(self, mock_fmt: object, tmp_path: Path) -> None:
        output = tmp_path / "output"
        config_path = tmp_path / "complyform.init.yaml"
        _write_init_config(config_path, output_directory=str(output))

        result = runner.invoke(
            app,
            ["generate", f"--config={config_path}"],
        )
        assert result.exit_code == 0, result.output
        assert (output / "providers.tf").exists()
        assert (output / "variables.tf").exists()


class TestGenerateMissingConfig:
    def test_raises_not_found(self, tmp_path: Path) -> None:
        result = runner.invoke(
            app,
            ["generate", f"--config={tmp_path / 'nonexistent.yaml'}"],
        )
        assert result.exit_code != 0


class TestGenerateNonemptyDirNoForce:
    @patch("complyform.core.greenfield.renderer._run_fmt")
    def test_raises_not_empty(self, mock_fmt: object, tmp_path: Path) -> None:
        output = tmp_path / "output"
        output.mkdir()
        (output / "existing.tf").write_text("# existing")

        config_path = tmp_path / "complyform.init.yaml"
        _write_init_config(config_path, output_directory=str(output))

        result = runner.invoke(
            app,
            ["generate", f"--config={config_path}"],
        )
        assert result.exit_code != 0


class TestGenerateNonemptyDirWithForce:
    @patch("complyform.core.greenfield.renderer._run_fmt")
    def test_succeeds_with_force(self, mock_fmt: object, tmp_path: Path) -> None:
        output = tmp_path / "output"
        output.mkdir()
        (output / "existing.tf").write_text("# existing")

        config_path = tmp_path / "complyform.init.yaml"
        _write_init_config(config_path, output_directory=str(output))

        result = runner.invoke(
            app,
            ["generate", f"--config={config_path}", "--force"],
        )
        assert result.exit_code == 0, result.output


class TestGenerateTierGatedFramework:
    def test_tier_error(self, tmp_path: Path) -> None:
        """Frameworks not in community tier raise error on generate."""
        output = tmp_path / "output"
        config_path = tmp_path / "complyform.init.yaml"
        data = {
            "version": "1",
            "project": {
                "cloud": "gcp",
                "project_id": "my-test-project",
                "region": "us-central1",
            },
            "compliance": {
                "frameworks": ["hipaa"],  # not in community tier
            },
            "services": [
                {
                    "id": "gcs",
                    "display_name": "Cloud Storage",
                    "category": "object_storage",
                },
            ],
            "output": {"directory": str(output)},
            "metadata": {
                "generated_by": "complyform",
                "generated_at": "2026-01-01T00:00:00Z",
                "cli_version": "0.1.0",
                "tier": "community",
            },
        }
        config_path.write_text(yaml.dump(data), encoding="utf-8")

        result = runner.invoke(
            app,
            ["generate", f"--config={config_path}"],
        )
        assert result.exit_code != 0


class TestGenerateJsonOutput:
    @patch("complyform.core.greenfield.renderer._run_fmt")
    def test_json_envelope(self, mock_fmt: object, tmp_path: Path) -> None:
        output = tmp_path / "output"
        config_path = tmp_path / "complyform.init.yaml"
        _write_init_config(config_path, output_directory=str(output))

        result = runner.invoke(
            app,
            ["generate", f"--config={config_path}", "--format=json"],
        )
        assert result.exit_code == 0, result.output
        envelope = json.loads(result.stdout)
        assert envelope["command"] == "generate"
        assert envelope["cloud"] == "gcp"
        assert "files_generated" in envelope


class TestGenerateHelpPanel:
    def test_registered_under_greenfield(self) -> None:
        result = runner.invoke(app, ["--help"])
        assert result.exit_code == 0
        assert "generate" in result.output
        assert "Greenfield" in result.output
