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


class TestAuthCreateProjectApiTokenIntegration(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 = None # Will hold the created token for cleanup


    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 __create_project_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 test_create_project_api_token_valid_parameters(self):
        """Test successful creation of project API token with valid parameters."""
        
        self.created_token = self.__create_project_api_token()

        # Validate response structure
        for token_attr in self.__token_attrs:            
            self.assertIn(token_attr, self.created_token, f"Response should have a '{token_attr}' key")

        # Validate specific attributes
        self.assertEqual(self.created_token["name"], self.test_token_name, "Token name should match requested name")
        self.assertEqual(self.created_token["status"], "Active", "New tokens should be active by default")


    def test_create_project_api_token_without_description(self):
        """Test successful creation of project API token without description."""

        with self.assertRaises(APIResponseError) as exception:
            self.created_token = self.__create_project_api_token(description="")

        self.assertIn(
            "Input data is missing (required %1) Description",
            str(exception.exception),
            "Expected error message about missing description when empty string is provided"
        )


    def test_create_project_api_token_long_description(self):
        """Test creation with long description."""
        long_description = "A" * 500  # Very long description
        
        self.created_token = self.__create_project_api_token(
            description=long_description
        )
        self.assertEqual(
            len(self.created_token["description"]), 200,
              "Long description should be shortened"
        )


    def test_create_project_api_token_invalid_project_id(self):
        """Test error when using invalid project ID."""
        with self.assertRaises(APIResponseError) as exception:
            self.__create_project_api_token(project_id="invalid-project-id")

        self.assertIn(
            "Input data is missing (required %1) project-id",
            str(exception.exception),
            "Expected error message about missing project ID when invalid format is provided"
        )


    def test_create_project_api_token_empty_project_id(self):
        """Test error when project ID is empty."""
        with self.assertRaises(APIResponseError) as exception:
            self.__create_project_api_token(project_id="")

        self.assertIn(
            "Input data is missing (required %1) project-id",
            str(exception.exception),
            "Expected error about empty project ID"
        )


    def test_create_project_api_token_empty_name(self):
        """Test error when token name is empty."""
        with self.assertRaises(APIResponseError) as exception:
            self.__create_project_api_token(name="")

        self.assertIn(
            "Input data is missing (required %1) Name",
            str(exception.exception),
            "Expected error about empty token name"
        )


    def test_create_project_api_token_duplicate_name(self):
        """Test behavior when creating token with duplicate name."""
        duplicate_name = f"duplicate_test_{uuid.uuid4().hex[:8]}"
        
        # Create first token
        self.created_token = self.__create_project_api_token(name=duplicate_name)
        
        # Try to create second token with same name
        # Some APIs allow duplicates, others don't - test the actual behavior
        with self.assertRaises(APIResponseError) as exception:
            self.__create_project_api_token(name=duplicate_name)

        self.assertIn(
            "Token ‘name’ already exists",
            str(exception.exception),
            "Expected error about duplicate token name"
        )


    def test_create_project_api_token_unauthorized_access(self):
        """Test error when user doesn't have access to the project."""
        # 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.create_project_api_token(
                project_id=self.project_id,
                name=self.test_token_name
            )

        self.assertIn(
            "Unauthorized",
            str(exception.exception),
            "Expected authorization-related error message"
        )


    def test_create_project_api_token_no_access_to_project(self):
        """Test error when user has valid credentials but no access to specific project."""
        # Project ID that exists but user doesn't have access to
        restricted_project_id = "6f5c69f1-232d-47d6-84f8-8bec87946bbc"
        
        with self.assertRaises(APIResponseError) as exception:
            self.__create_project_api_token(project_id=restricted_project_id)

        self.assertIn(
            "Forbidden",
            str(exception.exception),
            "Expected access-related error message"
        )


    def test_create_project_api_token_very_long_name(self):
        """Test creation with very long token name."""
        long_name = f"very_long_token_name_{'x' * 200}"

        with self.assertRaises(APIResponseError) as exception:
            self.__create_project_api_token(name=long_name)
        self.assertIn(
            "Not Found",
            str(exception.exception),
            "Expected error about name length limit"
        )