"""Tests for complyform.core.greenfield.config — InitConfig model."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

if TYPE_CHECKING:
    from pathlib import Path
import yaml

from complyform.core.errors import InitConfigNotFoundError, InitConfigVersionError
from complyform.core.greenfield.config import (
    InitConfig,
    ServiceEntry,
    load_init_config,
    save_init_config,
)


def _make_config(**overrides: object) -> InitConfig:
    defaults = {
        "cloud": "gcp",
        "project_id": "my-test-project",
        "region": "us-central1",
        "frameworks": ["soc2"],
        "services": [
            ServiceEntry(id="cloudsql", display_name="Cloud SQL", category="database")
        ],
        "output_directory": "./infra",
        "generated_at": "2026-01-01T00:00:00Z",
        "cli_version": "0.1.0",
        "tier": "community",
    }
    defaults.update(overrides)
    return InitConfig(**defaults)  # type: ignore[arg-type]


class TestLoadValidConfig:
    def test_round_trip(self, tmp_path: Path) -> None:
        config = _make_config()
        path = tmp_path / "complyform.init.yaml"
        save_init_config(config, path)
        loaded = load_init_config(path)

        assert loaded.cloud == config.cloud
        assert loaded.project_id == config.project_id
        assert loaded.region == config.region
        assert loaded.frameworks == config.frameworks
        assert len(loaded.services) == len(config.services)
        assert loaded.services[0].id == "cloudsql"
        assert loaded.output_directory == config.output_directory
        assert loaded.cli_version == config.cli_version
        assert loaded.tier == config.tier


class TestLoadMissingFile:
    def test_raises_not_found(self, tmp_path: Path) -> None:
        with pytest.raises(InitConfigNotFoundError):
            load_init_config(tmp_path / "nonexistent.yaml")


class TestLoadInvalidVersion:
    def test_raises_version_error(self, tmp_path: Path) -> None:
        path = tmp_path / "complyform.init.yaml"
        path.write_text(
            yaml.dump({"version": "99", "project": {}, "compliance": {}}),
            encoding="utf-8",
        )
        with pytest.raises(InitConfigVersionError):
            load_init_config(path)


class TestSaveYamlStructure:
    def test_nested_keys(self, tmp_path: Path) -> None:
        config = _make_config()
        path = tmp_path / "complyform.init.yaml"
        save_init_config(config, path)

        raw = yaml.safe_load(path.read_text(encoding="utf-8"))
        assert "version" in raw
        assert "project" in raw
        assert "compliance" in raw
        assert "services" in raw
        assert "output" in raw
        assert "metadata" in raw
        assert raw["project"]["cloud"] == "gcp"
        assert raw["project"]["project_id"] == "my-test-project"
        assert raw["compliance"]["frameworks"] == ["soc2"]
        assert raw["output"]["directory"] == "./infra"

    def test_header_comment(self, tmp_path: Path) -> None:
        config = _make_config()
        path = tmp_path / "complyform.init.yaml"
        save_init_config(config, path)
        text = path.read_text(encoding="utf-8")
        assert "# complyform.init.yaml" in text
        assert "complyform generate" in text


class TestConfigWithOptionalOrgId:
    def test_none_org_id_omitted(self, tmp_path: Path) -> None:
        config = _make_config(org_id=None)
        path = tmp_path / "complyform.init.yaml"
        save_init_config(config, path)

        raw = yaml.safe_load(path.read_text(encoding="utf-8"))
        assert "org_id" not in raw["project"]

    def test_org_id_present(self, tmp_path: Path) -> None:
        config = _make_config(org_id="123456789")
        path = tmp_path / "complyform.init.yaml"
        save_init_config(config, path)

        raw = yaml.safe_load(path.read_text(encoding="utf-8"))
        assert raw["project"]["org_id"] == "123456789"

        loaded = load_init_config(path)
        assert loaded.org_id == "123456789"
