from unittest import TestCase
import uuid
from pygeai.auth.clients import AuthClient
from pygeai.core.common.exceptions import APIResponseError 


class TestAuthUpdateProjectApiTokenIntegration(TestCase):
    __token_attrs = [
        'description', 'id', 'name', 'scope', 'status', 'timestamp'
    ]    

    def setUp(self):
        """
        Set up the test environment.
        """
        self.auth_client = AuthClient(alias="org")
        self.project_id = "be4889df-cacc-4e6f-b3bb-153c4ac0d168"
        self.test_token_name = f"test_token_{uuid.uuid4().hex[:8]}"
        self.created_token = self.__load_api_token()

    def __load_api_token(self, project_id=None, name=None, description=None):
        """
        Helper method to call create_project_api_token with default or custom parameters.
        """
        return self.auth_client.create_project_api_token(
            project_id=project_id if project_id is not None else self.project_id,
            name=name if name is not None else self.test_token_name,
            description="Test token created during integration testing" if description is None else description
        )

    def __update_project_api_token(self, api_token_id=None, description=None, status="Active"):
        """
        Helper method to call update_project_api_token with default or custom parameters.
        """
        return self.auth_client.update_project_api_token(
            api_token_id=api_token_id if api_token_id is not None else self.created_token["id"],
            description=description if description is not None else self.created_token["description"],
            status=status
        )
    

    def tearDown(self):
        """
        Clean up after each test if necessary.
        This can be used to delete the created token or reset the state.
        """
        if self.created_token:
            self.auth_client.delete_project_api_token(self.created_token["id"])


    def test_update_project_api_token_description_only(self):
        """Test successful update of token description only."""
        new_description = f"Updated description {uuid.uuid4().hex[:8]}"
        
        response = self.__update_project_api_token(description=new_description)

        # Validate response structure - might contain update messages or updated token info
        for token_attr in self.__token_attrs:            
            self.assertIn(token_attr, response, f"Response should have a '{token_attr}' key")
        
        # Response might contain success message or updated token data
        if "description" in response:
            self.assertEqual(response["description"], new_description, "Description should be updated")


    def test_update_project_api_token_status_only(self):
        """Test successful update of token status only."""
        valid_statuses = ["Active", "Blocked"]
        
        for status in valid_statuses:
            with self.subTest(status=status):
                response = self.__update_project_api_token(status=status)
                
                # Response might contain success message or updated token data
                if "status" in response:
                    self.assertEqual(
                        response["status"],
                        status,
                         f"Status should be updated to {status}"
                    )


    def test_update_project_api_token_both_fields(self):
        """Test successful update of both description and status."""
        new_description = f"Both fields updated {uuid.uuid4().hex[:8]}"
        new_status = "Blocked"
        
        response = self.__update_project_api_token(
            description=new_description,
            status=new_status
        )

        self.assertIsInstance(response, dict, "Response should be a dictionary")
        
        # Validate updates if response contains the token data
        self.assertEqual(response["description"], new_description)
        self.assertEqual(response["status"], new_status)


    def test_update_project_api_token_empty_description(self):
        """Test update with empty description."""
        with self.assertRaises(APIResponseError) as exception:
            self.__update_project_api_token(description="")
        
        # Empty description should be allowed
        self.assertIn(
            "Input data is missing (required %1) Description",
            str(exception.exception),
            "Empty description should be accepted"
        )


    def test_update_project_api_token_invalid_status(self):
        """Test error when using invalid status values."""
        invalid_statuses = ["inactive", "disabled"]
        
        for invalid_status in invalid_statuses:
            with self.subTest(status=invalid_status):
                with self.assertRaises(APIResponseError) as exception:
                    self.__update_project_api_token(status=invalid_status)

                self.assertIn(
                    f"Cannot update: [ {invalid_status} ] is not a valid status",
                    str(exception.exception),
                    f"Expected error about invalid status for '{invalid_status}'"
                )


    def test_update_project_api_token_invalid_token_id(self):
        """Test error when using invalid token ID format."""
        invalid_id = "invalid-token-id"        
       
        with self.assertRaises(APIResponseError) as exception:
            self.__update_project_api_token(
                api_token_id=invalid_id,
                description="test update"
            )

        self.assertIn(
            "Not Found",
            str(exception.exception),
            f"Expected error about invalid token ID format for {invalid_id}"
        )


    def test_update_project_api_token_unauthorized_access(self):
        """Test error when user doesn't have access to the token."""
        # Create a client with invalid credentials
        unauthorized_client = AuthClient(api_key="invalid", base_url="https://api.beta.saia.ai")
        
        with self.assertRaises(APIResponseError) as exception:
            unauthorized_client.update_project_api_token(api_token_id=self.created_token["id"])

        self.assertIn(
            "Unauthorized",
            str(exception.exception),
            "Expected error about unauthorized access when updating token with invalid credentials"
        )


    def test_update_project_api_token_long_description(self):
        """Test update with very long description."""
        long_description = "A" * 1000  # Very long description

        updated_token = self.__update_project_api_token(description=long_description)
        self.assertEqual(
            len(updated_token["description"]), 200,
              "Long description should be shortened"
        )


    def test_update_project_api_token_status_transitions(self):
        """Test valid status transitions."""
        status_transitions = [
            ("Active", "Blocked"),
            ("Blocked", "Active"),
        ]
        
        for from_status, to_status in status_transitions:
            with self.subTest(transition=f"{from_status} -> {to_status}"):
                # First set to from_status
                updated_token = self.__update_project_api_token(status=from_status)
                self.assertEqual(
                    updated_token["status"],
                    from_status,
                    f"Status should be updated to {from_status}"
                )

                # Then transition to to_status
                updated_token = self.__update_project_api_token(status=to_status)
                self.assertEqual(
                    updated_token["status"],
                    to_status,
                    f"Status should be updated to {to_status}"
                )