"""Tests for the template engine utilities."""

from __future__ import annotations

from pathlib import Path

import pytest

from prisme.utils.template_engine import (
    TemplateRenderer,
    comment_filter,
    create_template_environment,
    double_quote_filter,
    indent_filter,
    quote_filter,
    render_template_string,
)


class TestIndentFilter:
    """Tests for indent_filter."""

    def test_default_indent(self) -> None:
        result = indent_filter("line1\nline2\nline3")
        assert result == "line1\n    line2\n    line3"

    def test_custom_width(self) -> None:
        result = indent_filter("line1\nline2", width=2)
        assert result == "line1\n  line2"

    def test_indent_first_line(self) -> None:
        result = indent_filter("line1\nline2", first=True)
        assert result == "    line1\n    line2"

    def test_empty_lines_preserved(self) -> None:
        result = indent_filter("line1\n\nline3")
        assert result == "line1\n\n    line3"

    def test_single_line(self) -> None:
        result = indent_filter("single")
        assert result == "single"

    def test_single_line_with_first(self) -> None:
        result = indent_filter("single", first=True)
        assert result == "    single"


class TestQuoteFilter:
    """Tests for quote_filter."""

    def test_basic_quote(self) -> None:
        assert quote_filter("hello") == "'hello'"

    def test_escape_single_quotes(self) -> None:
        assert quote_filter("it's") == "'it\\'s'"

    def test_escape_backslashes(self) -> None:
        assert quote_filter("path\\to") == "'path\\\\to'"


class TestDoubleQuoteFilter:
    """Tests for double_quote_filter."""

    def test_basic_double_quote(self) -> None:
        assert double_quote_filter("hello") == '"hello"'

    def test_escape_double_quotes(self) -> None:
        assert double_quote_filter('say "hi"') == '"say \\"hi\\""'

    def test_escape_backslashes(self) -> None:
        assert double_quote_filter("path\\to") == '"path\\\\to"'


class TestCommentFilter:
    """Tests for comment_filter."""

    def test_python_style(self) -> None:
        result = comment_filter("line1\nline2", style="python")
        assert result == "# line1\n# line2"

    def test_js_style(self) -> None:
        result = comment_filter("line1\nline2", style="js")
        assert result == "// line1\n// line2"

    def test_javascript_style(self) -> None:
        result = comment_filter("line1", style="javascript")
        assert result == "// line1"

    def test_typescript_style(self) -> None:
        result = comment_filter("line1", style="typescript")
        assert result == "// line1"

    def test_sql_style(self) -> None:
        result = comment_filter("line1\nline2", style="sql")
        assert result == "-- line1\n-- line2"

    def test_default_style_is_python(self) -> None:
        result = comment_filter("line1")
        assert result == "# line1"

    def test_unknown_style_defaults_to_hash(self) -> None:
        result = comment_filter("line1", style="unknown")
        assert result == "# line1"

    def test_empty_lines_in_comment(self) -> None:
        result = comment_filter("line1\n\nline3", style="python")
        assert result == "# line1\n#\n# line3"


class TestCreateTemplateEnvironment:
    """Tests for create_template_environment."""

    def test_creates_environment(self) -> None:
        env = create_template_environment()
        assert env is not None

    def test_has_case_conversion_filters(self) -> None:
        env = create_template_environment()
        assert "snake_case" in env.filters
        assert "pascal_case" in env.filters
        assert "camel_case" in env.filters
        assert "kebab_case" in env.filters
        assert "pluralize" in env.filters
        assert "singularize" in env.filters

    def test_has_utility_filters(self) -> None:
        env = create_template_environment()
        assert "indent" in env.filters
        assert "quote" in env.filters
        assert "double_quote" in env.filters
        assert "comment" in env.filters

    def test_custom_template_dirs(self, tmp_path: Path) -> None:
        template_dir = tmp_path / "templates"
        template_dir.mkdir()
        (template_dir / "test.txt").write_text("Hello {{ name }}")
        env = create_template_environment(template_dirs=[template_dir])
        template = env.get_template("test.txt")
        result = template.render(name="World")
        assert result == "Hello World"

    def test_no_package_loader(self) -> None:
        env = create_template_environment(enable_package_loader=False)
        assert env is not None


class TestRenderTemplateString:
    """Tests for render_template_string."""

    def test_basic_render(self) -> None:
        result = render_template_string("Hello {{ name }}!", {"name": "World"})
        assert result == "Hello World!"

    def test_with_filter(self) -> None:
        result = render_template_string("{{ name | snake_case }}", {"name": "CustomerOrder"})
        assert result == "customer_order"

    def test_with_conditionals(self) -> None:
        result = render_template_string("{% if show %}visible{% endif %}", {"show": True})
        assert result == "visible"


class TestTemplateRenderer:
    """Tests for TemplateRenderer class."""

    def test_render_string(self) -> None:
        renderer = TemplateRenderer()
        result = renderer.render_string("Hello {{ name }}!", {"name": "World"})
        assert result == "Hello World!"

    def test_render_string_caches_template(self) -> None:
        renderer = TemplateRenderer()
        template_str = "Hello {{ name }}!"
        renderer.render_string(template_str, {"name": "World"})
        assert template_str in renderer._string_templates
        # Second render should use cache
        result = renderer.render_string(template_str, {"name": "Cached"})
        assert result == "Hello Cached!"

    def test_render_file(self) -> None:
        renderer = TemplateRenderer()
        result = renderer.render_file(
            "common/headers/python_generated.jinja2",
            {"description": "Test module"},
        )
        assert len(result) > 0
        assert "Test module" in result

    def test_get_available_templates(self) -> None:
        renderer = TemplateRenderer()
        templates = renderer.get_available_templates()
        assert len(templates) > 0

    def test_get_available_templates_with_prefix(self) -> None:
        renderer = TemplateRenderer()
        templates = renderer.get_available_templates(prefix="backend/")
        assert all(t.startswith("backend/") for t in templates)

    def test_get_available_templates_no_loader(self) -> None:
        renderer = TemplateRenderer()
        renderer.env.loader = None
        assert renderer.get_available_templates() == []

    def test_validate_templates_exist_success(self) -> None:
        renderer = TemplateRenderer()
        templates = renderer.get_available_templates()
        if templates:
            assert renderer.validate_templates_exist([templates[0]]) is True

    def test_validate_templates_exist_failure(self) -> None:
        renderer = TemplateRenderer()
        with pytest.raises(FileNotFoundError, match="Missing required templates"):
            renderer.validate_templates_exist(["nonexistent/template.jinja2"])

    def test_validate_templates_no_loader(self) -> None:
        renderer = TemplateRenderer()
        renderer.env.loader = None
        with pytest.raises(FileNotFoundError, match="No template loader"):
            renderer.validate_templates_exist(["test.jinja2"])
