from orionis.foundation.config.session.entities.session import Session
from orionis.foundation.config.session.enums.same_site_policy import SameSitePolicy
from orionis.foundation.exceptions import OrionisIntegrityException
from orionis.test.cases.synchronous import SyncTestCase

class TestFoundationConfigSession(SyncTestCase):

    def testDefaultInitialization(self):
        """
        Verify default initialization of the Session instance.

        This method checks that all attributes of the Session instance are set to their correct default values,
        including the generation of the secret_key.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Create a Session instance with default parameters
        session = Session()

        # Assert that all default attribute values are as expected
        self.assertEqual(session.session_cookie, "orionis_session")
        self.assertEqual(session.max_age, 1800)
        self.assertEqual(session.same_site, SameSitePolicy.LAX.value)
        self.assertEqual(session.path, "/")
        self.assertFalse(session.https_only)
        self.assertIsNone(session.domain)

    def testSecretKeyValidation(self):
        """
        Validate the secret_key attribute for correct value and type.

        This method ensures that providing an invalid secret_key raises an OrionisIntegrityException.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with invalid secret_key values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(secret_key="")  # Empty string
        with self.assertRaises(OrionisIntegrityException):
            Session(secret_key=123)  # Non-string value

    def testSessionCookieValidation(self):
        """
        Validate the session_cookie attribute for correct value and type.

        This method ensures that invalid session_cookie values raise an OrionisIntegrityException.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with invalid session_cookie values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(session_cookie="")  # Empty string
        with self.assertRaises(OrionisIntegrityException):
            Session(session_cookie="my session")  # Contains space
        with self.assertRaises(OrionisIntegrityException):
            Session(session_cookie="session;")  # Contains semicolon

    def testMaxAgeValidation(self):
        """
        Validate the max_age attribute for correct value and type.

        This method ensures that invalid max_age values raise an OrionisIntegrityException.
        Also verifies that None is accepted as a valid value.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with invalid max_age values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(max_age="3600")  # String instead of int
        with self.assertRaises(OrionisIntegrityException):
            Session(max_age=-1)  # Negative value

        # Test None is acceptable for max_age
        session = Session(max_age=None)
        self.assertIsNone(session.max_age)

    def testSameSiteValidation(self):
        """
        Validate the same_site attribute for correct value and normalization.

        This method ensures that both string and enum inputs for same_site are handled correctly.
        Also checks that invalid values raise an OrionisIntegrityException.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Test string inputs (case-insensitive)
        session1 = Session(same_site="strict")
        self.assertEqual(session1.same_site, SameSitePolicy.STRICT.value)
        session2 = Session(same_site="NONE")
        self.assertEqual(session2.same_site, SameSitePolicy.NONE.value)

        # Test enum inputs
        session3 = Session(same_site=SameSitePolicy.LAX)
        self.assertEqual(session3.same_site, SameSitePolicy.LAX.value)

        # Attempt to initialize Session with invalid same_site values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(same_site="invalid")
        with self.assertRaises(OrionisIntegrityException):
            Session(same_site=123)

    def testPathValidation(self):
        """
        Validate the path attribute for correct value and type.

        This method ensures that invalid path values raise an OrionisIntegrityException.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with invalid path values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(path="")  # Empty string
        with self.assertRaises(OrionisIntegrityException):
            Session(path="api")  # Doesn't start with /
        with self.assertRaises(OrionisIntegrityException):
            Session(path=123)  # Non-string value

    def testHttpsOnlyValidation(self):
        """
        Validate the https_only attribute for correct type.

        This method ensures that non-boolean values for https_only raise an OrionisIntegrityException.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with invalid https_only values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(https_only="true")  # String instead of bool
        with self.assertRaises(OrionisIntegrityException):
            Session(https_only=1)  # Integer instead of bool

    def testDomainValidation(self):
        """
        Validate the domain attribute for correct value and type.

        This method ensures that invalid domain values raise an OrionisIntegrityException.
        Also verifies that None is accepted as a valid value.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with invalid domain values; should raise exception
        with self.assertRaises(OrionisIntegrityException):
            Session(domain=".example.com")  # Starts with dot
        with self.assertRaises(OrionisIntegrityException):
            Session(domain="example.com.")  # Ends with dot
        with self.assertRaises(OrionisIntegrityException):
            Session(domain="example..com")  # Contains consecutive dots

        # Test None is acceptable for domain
        session = Session(domain=None)
        self.assertIsNone(session.domain)

    def testToDictMethod(self):
        """
        Validate the dictionary output of the toDict method for Session.

        This method ensures that the toDict method returns a dictionary containing all fields with correct values.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Create a Session instance
        session = Session()

        # Convert the Session instance to a dictionary
        result = session.toDict()

        # Assert that the dictionary contains the expected keys and values
        self.assertIsInstance(result, dict)
        self.assertIn("secret_key", result)
        self.assertEqual(result["session_cookie"], "orionis_session")
        self.assertEqual(result["max_age"], 1800)
        self.assertEqual(result["same_site"], SameSitePolicy.LAX.value)
        self.assertEqual(result["path"], "/")
        self.assertFalse(result["https_only"])
        self.assertIsNone(result["domain"])

    def testKwOnlyInitialization(self):
        """
        Validate enforcement of keyword-only initialization for Session.

        This method ensures that the Session class enforces keyword-only arguments during initialization
        by raising a TypeError when positional arguments are provided.

        Returns
        -------
        None
            This method does not return a value. It asserts conditions for testing purposes.
        """
        # Attempt to initialize Session with positional arguments; should raise TypeError
        with self.assertRaises(TypeError):
            Session("key", "session")
