"""Tests for the TurboSEO configuration system."""

import tempfile
from pathlib import Path

import pytest

from turboseo.config import (
    ProjectConfig,
    ThresholdSettings,
    KeywordSettings,
    ContentSettings,
    load_config,
    save_config,
    find_project_root,
    get_config_dir,
    create_gitignore_entry,
)
from turboseo.config.projects import (
    ProjectInfo,
    list_projects,
    add_project,
    remove_project,
    get_project,
    _get_projects_file,
)


class TestProjectConfig:
    """Tests for ProjectConfig model."""

    def test_creates_with_name_only(self):
        """Test creating config with just a name."""
        config = ProjectConfig(name="test-project")
        assert config.name == "test-project"
        assert config.description == ""
        assert config.url == ""

    def test_creates_with_all_fields(self):
        """Test creating config with all fields."""
        config = ProjectConfig(
            name="my-blog",
            description="A tech blog",
            url="https://example.com",
            context="Some context here",
        )
        assert config.name == "my-blog"
        assert config.description == "A tech blog"
        assert config.url == "https://example.com"
        assert config.context == "Some context here"

    def test_has_default_thresholds(self):
        """Test config has default threshold settings."""
        config = ProjectConfig(name="test")
        assert config.thresholds.min_readability_score == 60
        assert config.thresholds.target_keyword_density == 1.5
        assert config.thresholds.max_keyword_density == 2.5

    def test_has_default_keywords(self):
        """Test config has default keyword settings."""
        config = ProjectConfig(name="test")
        assert config.keywords.primary == []
        assert config.keywords.secondary == []
        assert config.keywords.avoid == []

    def test_has_default_content_settings(self):
        """Test config has default content settings."""
        config = ProjectConfig(name="test")
        assert config.content.default_type == "blog_post"
        assert config.content.target_audience == "general"
        assert config.content.writing_style == "professional"

    def test_serializes_to_dict(self):
        """Test config can be serialized to dict."""
        config = ProjectConfig(name="test")
        data = config.model_dump()
        assert isinstance(data, dict)
        assert data["name"] == "test"
        assert "thresholds" in data
        assert "keywords" in data


class TestThresholdSettings:
    """Tests for ThresholdSettings model."""

    def test_default_values(self):
        """Test default threshold values."""
        t = ThresholdSettings()
        assert t.min_readability_score == 60
        assert t.target_flesch_min == 60
        assert t.target_flesch_max == 70
        assert t.max_sentence_length == 25
        assert t.target_keyword_density == 1.5
        assert t.max_keyword_density == 2.5
        assert t.min_transition_density == 0.5
        assert t.min_word_count == 300
        assert t.max_word_count == 5000
        assert t.strict_mode is False

    def test_custom_values(self):
        """Test custom threshold values."""
        t = ThresholdSettings(
            min_readability_score=70,
            max_keyword_density=3.0,
            strict_mode=True,
        )
        assert t.min_readability_score == 70
        assert t.max_keyword_density == 3.0
        assert t.strict_mode is True


class TestKeywordSettings:
    """Tests for KeywordSettings model."""

    def test_default_empty_lists(self):
        """Test default keyword lists are empty."""
        k = KeywordSettings()
        assert k.primary == []
        assert k.secondary == []
        assert k.avoid == []

    def test_custom_keywords(self):
        """Test setting custom keywords."""
        k = KeywordSettings(
            primary=["seo", "content"],
            secondary=["marketing", "writing"],
            avoid=["synergy", "leverage"],
        )
        assert k.primary == ["seo", "content"]
        assert k.secondary == ["marketing", "writing"]
        assert k.avoid == ["synergy", "leverage"]


class TestSaveAndLoadConfig:
    """Tests for saving and loading configuration."""

    def test_save_and_load_roundtrip(self):
        """Test saving and loading config preserves data."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)

            config = ProjectConfig(
                name="test-project",
                description="A test project",
                url="https://test.com",
            )
            config.thresholds.max_keyword_density = 3.0
            config.keywords.primary = ["test", "keyword"]

            save_config(config, project_path)
            loaded = load_config(project_path)

            assert loaded is not None
            assert loaded.name == "test-project"
            assert loaded.description == "A test project"
            assert loaded.url == "https://test.com"
            assert loaded.thresholds.max_keyword_density == 3.0
            assert loaded.keywords.primary == ["test", "keyword"]

    def test_save_creates_config_dir(self):
        """Test save creates .turboseo directory."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)
            config = ProjectConfig(name="test")

            config_file = save_config(config, project_path)

            assert (project_path / ".turboseo").is_dir()
            assert config_file.exists()

    def test_load_returns_none_when_no_config(self):
        """Test load returns None when no config exists."""
        with tempfile.TemporaryDirectory() as tmpdir:
            loaded = load_config(Path(tmpdir))
            assert loaded is None

    def test_saves_context_separately(self):
        """Test context is saved to separate file."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)
            config = ProjectConfig(
                name="test",
                context="This is the project context.",
            )

            save_config(config, project_path)

            context_file = project_path / ".turboseo" / "context.md"
            assert context_file.exists()
            assert context_file.read_text() == "This is the project context."

    def test_loads_context_from_file(self):
        """Test context is loaded from separate file."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)
            config = ProjectConfig(name="test", context="Test context")
            save_config(config, project_path)

            loaded = load_config(project_path)
            assert loaded.context == "Test context"


class TestFindProjectRoot:
    """Tests for find_project_root function."""

    def test_finds_root_in_current_dir(self):
        """Test finding root when in project directory."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir).resolve()
            (project_path / ".turboseo").mkdir()

            found = find_project_root(project_path)
            assert found == project_path

    def test_finds_root_in_parent(self):
        """Test finding root from subdirectory."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir).resolve()
            (project_path / ".turboseo").mkdir()
            subdir = project_path / "src" / "components"
            subdir.mkdir(parents=True)

            found = find_project_root(subdir)
            assert found == project_path

    def test_returns_none_when_no_root(self):
        """Test returns None when no project root found."""
        with tempfile.TemporaryDirectory() as tmpdir:
            found = find_project_root(Path(tmpdir))
            assert found is None


class TestGetConfigDir:
    """Tests for get_config_dir function."""

    def test_returns_correct_path(self):
        """Test returns .turboseo path."""
        path = Path("/some/project")
        config_dir = get_config_dir(path)
        assert config_dir == Path("/some/project/.turboseo")


class TestCreateGitignoreEntry:
    """Tests for create_gitignore_entry function."""

    def test_creates_gitignore_if_not_exists(self):
        """Test creates .gitignore if it doesn't exist."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)
            result = create_gitignore_entry(project_path)

            assert result is True
            gitignore = project_path / ".gitignore"
            assert gitignore.exists()
            assert ".turboseo/" in gitignore.read_text()

    def test_adds_to_existing_gitignore(self):
        """Test adds entry to existing .gitignore."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)
            gitignore = project_path / ".gitignore"
            gitignore.write_text("node_modules/\n")

            result = create_gitignore_entry(project_path)

            assert result is True
            content = gitignore.read_text()
            assert "node_modules/" in content
            assert ".turboseo/" in content

    def test_does_not_duplicate_entry(self):
        """Test doesn't add duplicate entry."""
        with tempfile.TemporaryDirectory() as tmpdir:
            project_path = Path(tmpdir)
            gitignore = project_path / ".gitignore"
            gitignore.write_text(".turboseo/\n")

            result = create_gitignore_entry(project_path)

            assert result is False
            content = gitignore.read_text()
            assert content.count(".turboseo") == 1


class TestProjectsRegistry:
    """Tests for global projects registry."""

    def test_add_and_list_project(self):
        """Test adding and listing a project."""
        with tempfile.TemporaryDirectory() as tmpdir:
            # Override global dir for testing
            import turboseo.config.projects as projects_module
            original_get_global_dir = projects_module.get_global_dir

            def mock_global_dir():
                return Path(tmpdir)

            projects_module.get_global_dir = mock_global_dir
            # Also clear any existing test data
            projects_file = Path(tmpdir) / "projects.toml"
            if projects_file.exists():
                projects_file.unlink()

            try:
                # Use a path that won't get symlink-resolved
                test_path = Path(tmpdir).resolve() / "test-project"
                add_project(
                    name="test-project",
                    path=test_path,
                    url="https://test.com",
                )

                all_projects = list_projects()
                assert len(all_projects) >= 1

                # Find our project
                found = None
                for p in all_projects:
                    if p.name == "test-project":
                        found = p
                        break

                assert found is not None
                assert found.path == str(test_path)
                assert found.url == "https://test.com"

            finally:
                projects_module.get_global_dir = original_get_global_dir

    def test_get_project_by_name(self):
        """Test getting project by name."""
        with tempfile.TemporaryDirectory() as tmpdir:
            import turboseo.config.projects as projects_module
            original_get_global_dir = projects_module.get_global_dir

            def mock_global_dir():
                return Path(tmpdir)

            projects_module.get_global_dir = mock_global_dir
            projects_file = Path(tmpdir) / "projects.toml"
            if projects_file.exists():
                projects_file.unlink()

            try:
                add_project(
                    name="my-project",
                    path=Path("/tmp/my-project"),
                )

                found = get_project("my-project")
                assert found is not None
                assert found.name == "my-project"

                # Case insensitive
                found = get_project("MY-PROJECT")
                assert found is not None

            finally:
                projects_module.get_global_dir = original_get_global_dir

    def test_remove_project(self):
        """Test removing a project."""
        with tempfile.TemporaryDirectory() as tmpdir:
            import turboseo.config.projects as projects_module
            original_get_global_dir = projects_module.get_global_dir

            def mock_global_dir():
                return Path(tmpdir)

            projects_module.get_global_dir = mock_global_dir
            projects_file = Path(tmpdir) / "projects.toml"
            if projects_file.exists():
                projects_file.unlink()

            try:
                add_project(name="to-remove", path=Path("/tmp/to-remove"))

                result = remove_project("to-remove")
                assert result is True

                found = get_project("to-remove")
                assert found is None

            finally:
                projects_module.get_global_dir = original_get_global_dir

    def test_remove_nonexistent_project(self):
        """Test removing non-existent project returns False."""
        with tempfile.TemporaryDirectory() as tmpdir:
            import turboseo.config.projects as projects_module
            original_get_global_dir = projects_module.get_global_dir

            def mock_global_dir():
                return Path(tmpdir)

            projects_module.get_global_dir = mock_global_dir

            try:
                result = remove_project("does-not-exist")
                assert result is False

            finally:
                projects_module.get_global_dir = original_get_global_dir


class TestProjectInfo:
    """Tests for ProjectInfo model."""

    def test_creates_project_info(self):
        """Test creating ProjectInfo."""
        info = ProjectInfo(
            name="test",
            path="/tmp/test",
            added="2025-01-01T00:00:00",
        )
        assert info.name == "test"
        assert info.path == "/tmp/test"
        assert info.url == ""
        assert info.description == ""

    def test_serializes_to_dict(self):
        """Test ProjectInfo serializes to dict."""
        info = ProjectInfo(
            name="test",
            path="/tmp/test",
            added="2025-01-01T00:00:00",
        )
        data = info.model_dump()
        assert isinstance(data, dict)
        assert data["name"] == "test"
