# #region Test.GitLLMExtension [C:3] [TYPE Module] [SEMANTICS test, git, llm, commit, message, generation]
# @BRIEF Tests for git/llm_extension.py — GitLLMExtension.suggest_commit_message.
# @RELATION BINDS_TO -> [GitLLMExtensionModule]
# @TEST_CONTRACT: suggest_commit_message -> str | LLM-based commit message
# @TEST_EDGE: empty_response -> fallback message
# @TEST_EDGE: missing_choices -> fallback message

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))

import os
os.environ.setdefault("SECRET_KEY", "test-secret-key-for-testing")
os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:")
os.environ.setdefault("AUTH_DATABASE_URL", "sqlite:///:memory:")

from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from src.plugins.git.llm_extension import GitLLMExtension


class TestGitLLMExtension:
    """GitLLMExtension — commit message generation via LLM."""

    def setup_method(self):
        self.mock_client = MagicMock()
        self.mock_client.default_model = "gpt-4o-mini"
        self.extension = GitLLMExtension(self.mock_client)

    def test_init_stores_client(self):
        """Client stored on init."""
        assert self.extension.client is self.mock_client

    @pytest.mark.asyncio
    async def test_suggest_commit_message_success(self):
        """Successful LLM response returns stripped content."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        mock_choice = MagicMock()
        mock_choice.message.content = "  feat: add new feature  "
        mock_response = MagicMock()
        mock_response.choices = [mock_choice]
        self.mock_client.client.chat.completions.create.return_value = mock_response

        result = await self.extension.suggest_commit_message(
            diff="+ new feature",
            history=["feat: old feature"],
        )

        assert result == "feat: add new feature"

    @pytest.mark.asyncio
    async def test_suggest_commit_message_empty_choices(self):
        """Response with no choices returns fallback message."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        mock_response = MagicMock()
        mock_response.choices = []
        mock_response.error = None
        self.mock_client.client.chat.completions.create.return_value = mock_response

        result = await self.extension.suggest_commit_message(
            diff="+ new feature",
            history=[],
        )

        assert result == "Update dashboard configurations (LLM generation failed)"

    @pytest.mark.asyncio
    async def test_suggest_commit_message_no_response(self):
        """None response returns fallback message."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        self.mock_client.client.chat.completions.create.return_value = None

        result = await self.extension.suggest_commit_message(
            diff="+ new feature",
            history=[],
        )

        assert result == "Update dashboard configurations (LLM generation failed)"

    @pytest.mark.asyncio
    async def test_suggest_commit_message_empty_history(self):
        """Empty history list is joined to empty string."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        mock_choice = MagicMock()
        mock_choice.message.content = "Initial commit"
        mock_response = MagicMock()
        mock_response.choices = [mock_choice]
        self.mock_client.client.chat.completions.create.return_value = mock_response

        result = await self.extension.suggest_commit_message(
            diff="+ initial",
            history=[],
        )

        assert result == "Initial commit"

    @pytest.mark.asyncio
    async def test_suggest_commit_message_with_history(self):
        """Multiple history entries joined by newline."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        mock_choice = MagicMock()
        mock_choice.message.content = "fix: bug"
        mock_response = MagicMock()
        mock_response.choices = [mock_choice]
        self.mock_client.client.chat.completions.create.return_value = mock_response

        result = await self.extension.suggest_commit_message(
            diff="- bug line",
            history=["feat: a", "fix: b"],
        )

        assert result == "fix: bug"

    @pytest.mark.asyncio
    async def test_suggest_commit_message_custom_prompt(self):
        """Custom prompt template is rendered and passed to LLM."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        mock_choice = MagicMock()
        mock_choice.message.content = "custom message"
        mock_response = MagicMock()
        mock_response.choices = [mock_choice]
        self.mock_client.client.chat.completions.create.return_value = mock_response

        with patch("src.plugins.git.llm_extension.render_prompt") as mock_render:
            mock_render.return_value = "Custom template output"
            await self.extension.suggest_commit_message(
                diff="+ change",
                history=["prev"],
                prompt_template="Custom template with {history} and {diff}",
            )

            mock_render.assert_called_once()
            call_args = mock_render.call_args[0]
            assert "Custom template" in call_args[0]

    @pytest.mark.asyncio
    async def test_suggest_commit_message_model_and_temp(self):
        """Correct model and temperature passed to LLM."""
        self.mock_client.client.chat.completions.create = AsyncMock()
        mock_choice = MagicMock()
        mock_choice.message.content = "msg"
        mock_response = MagicMock()
        mock_response.choices = [mock_choice]
        self.mock_client.client.chat.completions.create.return_value = mock_response

        await self.extension.suggest_commit_message(
            diff="+ change",
            history=["prev"],
        )

        call_kwargs = self.mock_client.client.chat.completions.create.call_args[1]
        assert call_kwargs["model"] == "gpt-4o-mini"
        assert call_kwargs["temperature"] == 0.7
        assert len(call_kwargs["messages"]) == 1
        assert call_kwargs["messages"][0]["role"] == "user"
# #endregion Test.GitLLMExtension
