"""Additional tests for spec_loader - covering load_project_spec, load_config, and edge cases."""

from __future__ import annotations

from pathlib import Path

import pytest

from prisme.spec.project import ProjectSpec
from prisme.utils.spec_loader import (
    SpecLoadError,
    load_config,
    load_domain_spec,
    load_project_spec,
)


class TestLoadProjectSpec:
    """Tests for load_project_spec."""

    def test_load_valid_project_spec(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "project.py"
        spec_file.write_text(
            """\
from prisme.spec.project import ProjectSpec

project = ProjectSpec(name="test-project")
"""
        )
        result = load_project_spec(spec_file)
        assert isinstance(result, ProjectSpec)
        assert result.name == "test-project"

    def test_load_via_project_spec_variable(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "project.py"
        spec_file.write_text(
            """\
from prisme.spec.project import ProjectSpec

project_spec = ProjectSpec(name="alias-test")
"""
        )
        result = load_project_spec(spec_file)
        assert result.name == "alias-test"

    def test_load_via_factory_function(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "project.py"
        spec_file.write_text(
            """\
from prisme.spec.project import ProjectSpec

def get_project():
    return ProjectSpec(name="factory-project")
"""
        )
        result = load_project_spec(spec_file)
        assert result.name == "factory-project"

    def test_load_via_create_project(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "project.py"
        spec_file.write_text(
            """\
from prisme.spec.project import ProjectSpec

def create_project():
    return ProjectSpec(name="created-project")
"""
        )
        result = load_project_spec(spec_file)
        assert result.name == "created-project"

    def test_file_not_found(self, tmp_path: Path) -> None:
        with pytest.raises(SpecLoadError, match="not found"):
            load_project_spec(tmp_path / "nonexistent.py")

    def test_non_python_file(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "project.yaml"
        spec_file.write_text("name: test")
        with pytest.raises(SpecLoadError, match="Python file"):
            load_project_spec(spec_file)

    def test_syntax_error(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "bad.py"
        spec_file.write_text("def broken(\n")
        with pytest.raises(SpecLoadError, match="Error executing"):
            load_project_spec(spec_file)

    def test_no_project_spec_found(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "empty.py"
        spec_file.write_text("x = 42\n")
        with pytest.raises(SpecLoadError, match="No ProjectSpec found"):
            load_project_spec(spec_file)

    def test_factory_error_raises(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "project.py"
        spec_file.write_text(
            """\
def get_project():
    raise RuntimeError("factory broken")
"""
        )
        with pytest.raises(SpecLoadError, match="Error calling"):
            load_project_spec(spec_file)


class TestLoadDomainSpec:
    """Tests for load_domain_spec alias."""

    def test_alias_works(self, tmp_path: Path) -> None:
        spec_file = tmp_path / "models.py"
        spec_file.write_text(
            """\
from prisme.spec.stack import StackSpec
from prisme.spec.model import ModelSpec
from prisme.spec.fields import FieldSpec, FieldType

spec = StackSpec(
    name="alias-test",
    version="1.0.0",
    models=[
        ModelSpec(
            name="Item",
            fields=[FieldSpec(name="name", type=FieldType.STRING, required=True)],
        )
    ],
)
"""
        )
        result = load_domain_spec(spec_file)
        assert result.name == "alias-test"


class TestLoadConfig:
    """Tests for load_config."""

    def test_load_valid_config(self, tmp_path: Path) -> None:
        config_file = tmp_path / "prisme.toml"
        config_file.write_text(
            """\
prisme_version = "0.12.1"

[generation]
mode = "strict"
"""
        )
        result = load_config(config_file)
        assert result.generation.mode == "strict"

    def test_load_config_with_defaults(self, tmp_path: Path) -> None:
        config_file = tmp_path / "prisme.toml"
        config_file.write_text('prisme_version = "0.12.1"\n')
        result = load_config(config_file)
        assert result.generation.mode == "strict"

    def test_load_config_missing_version_raises(self, tmp_path: Path) -> None:
        from prisme.config.loader import ConfigLoadError

        config_file = tmp_path / "prisme.toml"
        config_file.write_text("")
        with pytest.raises(ConfigLoadError, match="Invalid configuration"):
            load_config(config_file)
