"""
Tests for Smart Card API

This module contains tests for the Smart Card API, which provides a simplified
interface for LLMs to interact with the card creation system.
"""

import asyncio
import os
import sys
import unittest
from unittest.mock import AsyncMock, MagicMock, patch

# Add the parent directory to the path so we can import the modules
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")))

from gchat.content_mapping.smart_card_api import (
    _card_validator,
    _content_mapping_engine,
    _parameter_inference_engine,
    _template_manager,
    create_card_from_description,
    create_card_from_template,
    parse_natural_language_content,
    send_smart_card,
)


class TestSmartCardAPI(unittest.TestCase):
    """Test cases for the Smart Card API."""

    def setUp(self):
        """Set up test fixtures."""
        # Create mock for asyncio.to_thread
        self.to_thread_patcher = patch("asyncio.to_thread")
        self.mock_to_thread = self.to_thread_patcher.start()
        self.mock_to_thread.return_value = {
            "name": "spaces/123/messages/456",
            "createTime": "2025-07-03T12:00:00Z",
        }

        # Create mock for _get_chat_service_with_fallback
        self.get_service_patcher = patch(
            "gchat.content_mapping.smart_card_api._get_chat_service_with_fallback"
        )
        self.mock_get_service = self.get_service_patcher.start()

        # Mock chat service
        self.mock_chat_service = MagicMock()
        self.mock_messages = MagicMock()
        self.mock_spaces = MagicMock()
        self.mock_create = MagicMock()
        self.mock_execute = MagicMock()

        self.mock_chat_service.spaces.return_value = self.mock_spaces
        self.mock_spaces.messages.return_value = self.mock_messages
        self.mock_messages.create.return_value = self.mock_create
        self.mock_create.execute.return_value = {
            "name": "spaces/123/messages/456",
            "createTime": "2025-07-03T12:00:00Z",
        }

        self.mock_get_service.return_value = self.mock_chat_service

        # Create mock for _find_card_component
        self.find_component_patcher = patch(
            "gchat.content_mapping.smart_card_api._find_card_component"
        )
        self.mock_find_component = self.find_component_patcher.start()
        self.mock_find_component.return_value = [
            {
                "component": MagicMock(),
                "path": "card_framework.v2.Card",
                "score": 0.95,
                "type": "simple",
            }
        ]

        # Create mock for _create_card_from_component
        self.create_card_patcher = patch(
            "gchat.content_mapping.smart_card_api._create_card_from_component"
        )
        self.mock_create_card = self.create_card_patcher.start()
        self.mock_create_card.return_value = {
            "header": {"title": "Test Card"},
            "sections": [],
        }

        # Create mock for _convert_card_to_google_format
        self.convert_card_patcher = patch(
            "gchat.content_mapping.smart_card_api._convert_card_to_google_format"
        )
        self.mock_convert_card = self.convert_card_patcher.start()
        self.mock_convert_card.return_value = {
            "cardId": "test_card_123",
            "card": {"header": {"title": "Test Card"}, "sections": []},
        }

        # Create mock for Message
        self.message_patcher = patch("gchat.content_mapping.smart_card_api.Message")
        self.mock_message_class = self.message_patcher.start()
        self.mock_message = MagicMock()
        self.mock_message.cards_v2 = []
        self.mock_message.render.return_value = {
            "cardsV2": [
                {
                    "cardId": "test_card_123",
                    "card": {"header": {"title": "Test Card"}, "sections": []},
                }
            ]
        }
        self.mock_message_class.return_value = self.mock_message

        # Create mock for requests
        self.requests_patcher = patch("requests.post")
        self.mock_requests_post = self.requests_patcher.start()
        self.mock_response = MagicMock()
        self.mock_response.status_code = 200
        self.mock_requests_post.return_value = self.mock_response

    def tearDown(self):
        """Tear down test fixtures."""
        self.to_thread_patcher.stop()
        self.get_service_patcher.stop()
        self.find_component_patcher.stop()
        self.create_card_patcher.stop()
        self.convert_card_patcher.stop()
        self.message_patcher.stop()
        self.requests_patcher.stop()

    def test_parse_natural_language_content(self):
        """Test parsing natural language content."""
        # Test with pipe separator
        content = "Title: Meeting Update | Text: Team standup at 2 PM | Button: Join -> https://meet.google.com/abc"
        result = parse_natural_language_content(content)

        self.assertEqual(result["title"], "Meeting Update")
        self.assertEqual(result["text"], "Team standup at 2 PM")
        self.assertEqual(len(result["buttons"]), 1)
        self.assertEqual(result["buttons"][0]["text"], "Join")
        self.assertEqual(result["buttons"][0]["url"], "https://meet.google.com/abc")

        # Test with newline separator
        content = """
        Title: Project Status
        Text: Sprint completed successfully
        Button: View Dashboard -> https://dashboard.example.com
        """
        result = parse_natural_language_content(content)

        self.assertEqual(result["title"], "Project Status")
        self.assertEqual(result["text"], "Sprint completed successfully")
        self.assertEqual(len(result["buttons"]), 1)
        self.assertEqual(result["buttons"][0]["text"], "View Dashboard")
        self.assertEqual(result["buttons"][0]["url"], "https://dashboard.example.com")

    @patch("gchat.content_mapping.smart_card_api._ensure_template_manager_initialized")
    async def test_send_smart_card(self, mock_ensure_initialized):
        """Test sending a smart card."""
        # Mock content mapping engine
        _content_mapping_engine.parse_content = MagicMock()
        _content_mapping_engine.parse_content.return_value = {
            "header": {"title": "Meeting Update"},
            "sections": [
                {"widgets": [{"textParagraph": {"text": "Team standup at 2 PM"}}]}
            ],
        }

        # Mock card validator
        _card_validator.validate_card_structure = MagicMock()
        _card_validator.validate_card_structure.return_value = (True, [])

        # Test sending via API
        result = await send_smart_card(
            user_google_email="user@example.com",
            space_id="spaces/123",
            content="Title: Meeting Update | Text: Team standup at 2 PM",
            style="announcement",
        )

        # Verify the result
        self.assertIn("✅ Smart card sent to space", result)
        self.assertIn("spaces/123", result)
        self.assertIn("user@example.com", result)

        # Verify the mocks were called correctly
        mock_ensure_initialized.assert_called_once()
        _content_mapping_engine.parse_content.assert_called_once()
        self.mock_find_component.assert_called_once_with("header card")
        self.mock_create_card.assert_called_once()
        self.mock_convert_card.assert_called_once()
        self.mock_get_service.assert_called_once_with("user@example.com")

        # Test sending via webhook
        result = await send_smart_card(
            user_google_email="user@example.com",
            space_id="spaces/123",
            content="Title: Meeting Update | Text: Team standup at 2 PM",
            style="default",
            webhook_url="https://chat.googleapis.com/v1/spaces/123/messages",
        )

        # Verify the result
        self.assertIn("✅ Smart card sent successfully via webhook", result)

        # Verify the webhook was called
        self.mock_requests_post.assert_called_once()

    @patch("gchat.content_mapping.smart_card_api._ensure_template_manager_initialized")
    async def test_create_card_from_template(self, mock_ensure_initialized):
        """Test creating a card from a template."""
        # Mock template manager
        _template_manager.find_templates = AsyncMock()
        _template_manager.find_templates.return_value = [
            {
                "template_id": "template_123",
                "name": "Meeting Template",
                "description": "Template for meeting announcements",
            }
        ]

        _template_manager.get_template = AsyncMock()
        _template_manager.get_template.return_value = {
            "template_id": "template_123",
            "name": "Meeting Template",
            "description": "Template for meeting announcements",
            "template": {
                "header": {"title": "{meeting_title}"},
                "sections": [
                    {"widgets": [{"textParagraph": {"text": "{meeting_time}"}}]}
                ],
            },
            "placeholders": {
                "meeting_title": "header.title",
                "meeting_time": "sections.0.widgets.0.textParagraph.text",
            },
        }

        _template_manager.apply_template = MagicMock()
        _template_manager.apply_template.return_value = {
            "header": {"title": "Team Standup"},
            "sections": [{"widgets": [{"textParagraph": {"text": "2 PM today"}}]}],
        }

        # Test sending via API
        result = await create_card_from_template(
            template_name="Meeting Template",
            content={"meeting_title": "Team Standup", "meeting_time": "2 PM today"},
            user_google_email="user@example.com",
            space_id="spaces/123",
        )

        # Verify the result
        self.assertIn("✅ Template card sent to space", result)
        self.assertIn("spaces/123", result)
        self.assertIn("user@example.com", result)

        # Verify the mocks were called correctly
        mock_ensure_initialized.assert_called_once()
        _template_manager.find_templates.assert_called_once_with("Meeting Template")
        _template_manager.get_template.assert_called_once_with("template_123")
        _template_manager.apply_template.assert_called_once()
        self.mock_get_service.assert_called_once_with("user@example.com")

    async def test_create_card_from_description(self):
        """Test creating a card from a description without sending."""
        # Mock content mapping engine
        _content_mapping_engine.parse_content = MagicMock()
        _content_mapping_engine.parse_content.return_value = {
            "header": {"title": "Meeting Update"},
            "sections": [
                {"widgets": [{"textParagraph": {"text": "Team standup at 2 PM"}}]}
            ],
        }

        # Mock parameter inference engine
        _parameter_inference_engine.infer_card_type = MagicMock()
        _parameter_inference_engine.infer_card_type.return_value = "simple"

        # Mock card validator
        _card_validator.validate_card_structure = MagicMock()
        _card_validator.validate_card_structure.return_value = (True, [])

        # Test creating card
        result = await create_card_from_description(
            description="Title: Meeting Update | Text: Team standup at 2 PM"
        )

        # Verify the result
        self.assertEqual(result["card_type"], "simple")
        self.assertIn("card", result)

        # Verify the mocks were called correctly
        _content_mapping_engine.parse_content.assert_called_once()
        _parameter_inference_engine.infer_card_type.assert_called_once()
        self.mock_find_component.assert_called_once_with("simple card")
        self.mock_create_card.assert_called_once()


def run_async_test(coro):
    """Helper function to run async tests."""
    return asyncio.run(coro)


if __name__ == "__main__":
    unittest.main()
