from orionis.luminate.foundation.config.exceptions.integrity import OrionisIntegrityException
from orionis.luminate.foundation.config.filesystems.entitites.aws import S3
from orionis.unittesting import TestCase

class TestConfigS3(TestCase):
    """
    Test cases for the S3 storage configuration class.
    """

    async def testDefaultValues(self):
        """
        Test that S3 instance is created with correct default values.
        Verifies all default values match expected defaults from class definition.
        """
        s3 = S3()
        self.assertEqual(s3.key, "")
        self.assertEqual(s3.secret, "")
        self.assertEqual(s3.region, "us-east-1")
        self.assertEqual(s3.bucket, "")
        self.assertIsNone(s3.url)
        self.assertIsNone(s3.endpoint)
        self.assertFalse(s3.use_path_style_endpoint)
        self.assertFalse(s3.throw)

    async def testRequiredFieldValidation(self):
        """
        Test validation of required fields.
        Verifies that region must be a non-empty string.
        """
        # Test empty region
        with self.assertRaises(OrionisIntegrityException):
            S3(region="")

        # Test non-string region
        with self.assertRaises(OrionisIntegrityException):
            S3(region=123)

    async def testOptionalFieldValidation(self):
        """
        Test validation of optional fields.
        Verifies that optional fields accept None or proper types.
        """
        # Valid optional configurations
        try:
            S3(url=None, endpoint=None)
            S3(url="https://example.com", endpoint="https://s3.example.com")
        except OrionisIntegrityException:
            self.fail("Valid optional configurations should not raise exceptions")

        # Invalid optional configurations
        with self.assertRaises(OrionisIntegrityException):
            S3(url=123)
        with self.assertRaises(OrionisIntegrityException):
            S3(endpoint=[])

    async def testBooleanFieldValidation(self):
        """
        Test validation of boolean fields.
        Verifies that boolean fields only accept boolean values.
        """
        # Test use_path_style_endpoint
        with self.assertRaises(OrionisIntegrityException):
            S3(use_path_style_endpoint="true")

        # Test throw
        with self.assertRaises(OrionisIntegrityException):
            S3(throw=1)

    async def testCustomValues(self):
        """
        Test that custom values are properly stored and validated.
        Verifies custom configuration values are correctly handled.
        """
        custom_s3 = S3(
            key="AKIAEXAMPLE",
            secret="secret123",
            region="eu-west-1",
            bucket="my-bucket",
            url="https://my-bucket.s3.amazonaws.com",
            endpoint="https://s3.eu-west-1.amazonaws.com",
            use_path_style_endpoint=True,
            throw=True
        )

        self.assertEqual(custom_s3.key, "AKIAEXAMPLE")
        self.assertEqual(custom_s3.secret, "secret123")
        self.assertEqual(custom_s3.region, "eu-west-1")
        self.assertEqual(custom_s3.bucket, "my-bucket")
        self.assertEqual(custom_s3.url, "https://my-bucket.s3.amazonaws.com")
        self.assertEqual(custom_s3.endpoint, "https://s3.eu-west-1.amazonaws.com")
        self.assertTrue(custom_s3.use_path_style_endpoint)
        self.assertTrue(custom_s3.throw)

    async def testToDictMethod(self):
        """
        Test that toDict returns proper dictionary representation.
        Verifies all attributes are correctly included in dictionary.
        """
        s3 = S3()
        s3_dict = s3.toDict()

        self.assertIsInstance(s3_dict, dict)
        self.assertEqual(s3_dict['key'], "")
        self.assertEqual(s3_dict['secret'], "")
        self.assertEqual(s3_dict['region'], "us-east-1")
        self.assertEqual(s3_dict['bucket'], "")
        self.assertIsNone(s3_dict['url'])
        self.assertIsNone(s3_dict['endpoint'])
        self.assertFalse(s3_dict['use_path_style_endpoint'])
        self.assertFalse(s3_dict['throw'])

    async def testHashability(self):
        """
        Test that S3 maintains hashability due to unsafe_hash=True.
        Verifies that S3 instances can be used in sets and as dictionary keys.
        """
        s3_1 = S3()
        s3_2 = S3()
        s3_set = {s3_1, s3_2}

        self.assertEqual(len(s3_set), 1)

        custom_s3 = S3(bucket="custom-bucket")
        s3_set.add(custom_s3)
        self.assertEqual(len(s3_set), 2)

    async def testKwOnlyInitialization(self):
        """
        Test that S3 enforces keyword-only initialization.
        Verifies that positional arguments are not allowed for initialization.
        """
        with self.assertRaises(TypeError):
            S3("key", "secret", "region")  # Should fail as it requires keyword arguments