"""
Tests for IssueWriter functionality.
"""

import json
import subprocess
import pytest
from unittest.mock import patch, MagicMock

from tddai.issue_writer import IssueWriter
from tddai.exceptions import IssueError
from tddai.config import TddaiConfig
from pathlib import Path


class TestIssueWriter:
    """Test suite for IssueWriter class."""

    def _get_test_config(self):
        """Get a valid test configuration."""
        return TddaiConfig(
            workspace_dir=Path(".test_workspace"),
            gitea_url="http://localhost:3000",
            repo_owner="test_owner",
            repo_name="test_repo"
        )

    def test_init_with_auth_token(self):
        """Test IssueWriter initialization with auth token."""
        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        assert writer.auth_token == "test-token"

    def test_init_without_auth_token_uses_env(self):
        """Test IssueWriter uses environment variable when no token provided."""
        config = self._get_test_config()
        with patch.dict('os.environ', {'GITEA_API_TOKEN': 'env-token'}):
            writer = IssueWriter(config=config)
            assert writer.auth_token == "env-token"

    def test_update_issue_without_auth_token_raises_error(self):
        """Test that updating without auth token raises IssueError."""
        config = self._get_test_config()
        with patch.dict('os.environ', {}, clear=True):
            writer = IssueWriter(config=config, auth_token=None)
            with pytest.raises(IssueError, match="Authentication token required"):
                writer.update_issue(1, {'title': 'New Title'})

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_success(self, mock_run):
        """Test successful issue update via PATCH."""
        # Mock successful response
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({
            'number': 1,
            'title': 'Updated Title',
            'body': 'Updated body',
            'state': 'open'
        })
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        result = writer.update_issue(1, {'title': 'Updated Title'})

        assert result['number'] == 1
        assert result['title'] == 'Updated Title'

        # Verify curl command was called correctly
        mock_run.assert_called_once()
        call_args = mock_run.call_args[0][0]
        assert 'curl' in call_args
        assert '-X' in call_args
        assert 'PATCH' in call_args
        assert 'Authorization: token test-token' in ' '.join(call_args)

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_with_error_response(self, mock_run):
        """Test issue update with API error response."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({'message': 'Issue not found'})
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        with pytest.raises(IssueError, match="Failed to update issue #1: Issue not found"):
            writer.update_issue(1, {'title': 'New Title'})

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_subprocess_error(self, mock_run):
        """Test issue update with subprocess error."""
        mock_run.side_effect = subprocess.CalledProcessError(1, 'curl')

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        with pytest.raises(IssueError, match="Failed to update issue #1"):
            writer.update_issue(1, {'title': 'New Title'})

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_json_decode_error(self, mock_run):
        """Test issue update with invalid JSON response."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = "invalid json"
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        with pytest.raises(IssueError, match="Failed to parse response data"):
            writer.update_issue(1, {'title': 'New Title'})

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_title(self, mock_run):
        """Test updating only issue title."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({'number': 1, 'title': 'New Title'})
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        result = writer.update_issue_title(1, 'New Title')

        assert result['title'] == 'New Title'

        # Verify the correct data was sent
        call_args = mock_run.call_args[0][0]
        json_data_index = call_args.index('-d') + 1
        sent_data = json.loads(call_args[json_data_index])
        assert sent_data == {'title': 'New Title'}

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_body(self, mock_run):
        """Test updating only issue body."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({'number': 1, 'body': 'New body content'})
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        result = writer.update_issue_body(1, 'New body content')

        assert result['body'] == 'New body content'

    @patch('tddai.issue_writer.subprocess.run')
    def test_update_issue_state_valid(self, mock_run):
        """Test updating issue state with valid state."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({'number': 1, 'state': 'closed'})
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        result = writer.update_issue_state(1, 'closed')

        assert result['state'] == 'closed'

    def test_update_issue_state_invalid(self):
        """Test updating issue state with invalid state."""
        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        with pytest.raises(IssueError, match="Invalid state 'invalid'"):
            writer.update_issue_state(1, 'invalid')

    @patch('tddai.issue_writer.subprocess.run')
    def test_close_issue(self, mock_run):
        """Test closing an issue."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({'number': 1, 'state': 'closed'})
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        result = writer.close_issue(1)

        assert result['state'] == 'closed'

    @patch('tddai.issue_writer.subprocess.run')
    def test_reopen_issue(self, mock_run):
        """Test reopening an issue."""
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = json.dumps({'number': 1, 'state': 'open'})
        mock_result.stderr = ''
        mock_run.return_value = mock_result

        config = self._get_test_config()
        writer = IssueWriter(config=config, auth_token="test-token")
        result = writer.reopen_issue(1)

        assert result['state'] == 'open'