#!/usr/bin/env python3
"""Integration tests for all 5 core BlackAnt SDK methods."""

import unittest
import os
from unittest.mock import Mock, patch, MagicMock

import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src'))

from blackant import BlackAntClient
from blackant.exceptions import BlackAntDockerError


class TestCoreMethodsIntegration(unittest.TestCase):
    """Test all 5 core methods of BlackAnt SDK through unified client."""

    def setUp(self):
        """Set up test environment with comprehensive mocking."""
        # Mock all external dependencies
        self.patches = []

        # Mock Docker from_env
        docker_patch = patch('blackant.docker.builder.docker.from_env')
        self.mock_docker_from_env = docker_patch.start()
        self.patches.append(docker_patch)

        mock_docker_client = Mock()
        mock_docker_client.ping.return_value = True
        mock_docker_client.images.build.return_value = (Mock(id="sha256:test123", attrs={"Size": 100000}), [])
        mock_docker_client.images.push.return_value = [{"status": "Pushed"}]
        self.mock_docker_from_env.return_value = mock_docker_client

        # Mock HTTP requests for authentication
        http_patch = patch('blackant.auth.blackant_auth.requests.post')
        self.mock_auth_post = http_patch.start()
        self.patches.append(http_patch)

        mock_auth_response = Mock()
        mock_auth_response.status_code = 200
        mock_auth_response.json.return_value = {
            "access_token": "test_jwt_token_12345",
            "expires_in": 3600,
            "token_type": "Bearer"
        }
        self.mock_auth_post.return_value = mock_auth_response

        # Mock HTTP client for service operations
        http_client_patch = patch('blackant.http.client.HTTPClient.send_request')
        self.mock_http_send = http_client_patch.start()
        self.patches.append(http_client_patch)

        # Mock Docker config
        config_patch = patch('blackant.config.docker_config.get_docker_config')
        self.mock_get_config = config_patch.start()
        self.patches.append(config_patch)

        mock_config = Mock()
        mock_config.registry.url = "env.blackant.app"
        mock_config.registry.namespace = "systemdevelopers"
        mock_config.get_full_image_name.return_value = "env.blackant.app/systemdevelopers/test:v1.0.0"
        mock_config.get_build_args.return_value = {"SERVICE_NAME": "test"}
        mock_config.get_build_labels.return_value = {"test": "label"}
        mock_config.get_registry_credentials.return_value = {}
        self.mock_get_config.return_value = mock_config

        # Create test directories
        os.makedirs("src/calculation/impl", exist_ok=True)
        with open("src/calculation/impl/test.py", "w") as f:
            f.write("print('test')")

        if not os.path.exists("Dockerfile"):
            with open("Dockerfile", "w") as f:
                f.write("FROM python:3.9\nCOPY impl/ /app/\nCMD python /app/test.py")

    def tearDown(self):
        """Clean up patches."""
        for patch_obj in self.patches:
            patch_obj.stop()

    def test_core_methods_error_handling(self):
        """Test error handling across core methods."""
        print("\nWARNING Testing Error Handling Across Core Methods")
        print("=" * 60)

        client = BlackAntClient(user="test@company.com", password="testpass123")

        # Test authentication error
        self.mock_auth_post.side_effect = Exception("Auth server unavailable")

        auth_result = client.authenticate()
        self.assertFalse(auth_result)
        print("   OK Authentication error handled gracefully")

        # Test connection error
        self.mock_http_send.side_effect = Exception("Network error")

        connection_result = client.test_connection()
        self.assertFalse(connection_result)
        print("   OK Connection error handled gracefully")

        # Test build service error (build might succeed but registration fail)
        # This is acceptable behavior - build succeeds but registration fails
        try:
            result = client.build_service("invalid-service")
            # Build should succeed but registration should fail
            self.assertFalse(result.get("service_registered", True))
            print("   OK Build service error handled gracefully (build succeeds, registration fails)")
        except BlackAntDockerError:
            print("   OK Build service error raises appropriate exception")

        print("\nOK Error handling verification complete")

    def test_client_context_manager(self):
        """Test BlackAnt client as context manager."""
        print("\n> Testing Client Context Manager")

        with BlackAntClient(user="test@company.com", password="testpass123") as client:
            self.assertIsNotNone(client)
            self.assertIsInstance(client, BlackAntClient)

        print("   OK Context manager works correctly")

    def test_client_representation(self):
        """Test client string representation."""
        client = BlackAntClient(user="test@company.com", password="testpass123")

        repr_str = repr(client)
        self.assertIn("BlackAntClient", repr_str)
        self.assertIn("test@company.com", repr_str)

        print(f"   > Client repr: {repr_str}")

    def test_additional_utility_methods(self):
        """Test additional utility methods."""
        print("\n> Testing Additional Utility Methods")

        client = BlackAntClient(user="test@company.com", password="testpass123")

        # Mock responses for utility methods
        get_response = Mock()
        get_response.status_code = 200
        get_response.json.return_value = {"id": "test-123", "name": "test-service"}
        get_response.raise_for_status = Mock()

        update_response = Mock()
        update_response.status_code = 200
        update_response.raise_for_status = Mock()

        delete_response = Mock()
        delete_response.status_code = 200
        delete_response.raise_for_status = Mock()

        status_response = Mock()
        status_response.status_code = 200
        status_response.json.return_value = {"state": "running", "uptime": "24h"}
        status_response.raise_for_status = Mock()

        self.mock_http_send.side_effect = [
            get_response, update_response, delete_response, status_response
        ]

        # Test get_service
        service = client.get_service(service_name="test-service")
        self.assertEqual(service["name"], "test-service")
        print("   OK get_service() works")

        # Test update_service
        success = client.update_service(service_name="test-service", update_data={"version": "2.0"})
        self.assertTrue(success)
        print("   OK update_service() works")

        # Test delete_service
        success = client.delete_service(service_name="test-service")
        self.assertTrue(success)
        print("   OK delete_service() works")

        # Test get_service_status
        status = client.get_service_status(service_name="test-service")
        self.assertEqual(status["state"], "running")
        print("   OK get_service_status() works")


if __name__ == '__main__':
    unittest.main(verbosity=2)