#!/usr/bin/env python3
"""Client Credentials authentication functional tests.

Tests BlackAnt client credentials flow authentication.
"""

import sys
import os
import unittest

# Add src to path for imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src'))

from blackant import BlackAntAuth, BlackAntClient
from blackant.exceptions import BlackAntAuthenticationError


class TestClientCredentialsOperations(unittest.TestCase):
    """Test client credentials authentication operations."""

    def setUp(self):
        """Set up test environment."""
        # Get client credentials from environment variables
        self.client_id = os.getenv("BLACKANT_TEST_CLIENT_ID")
        self.client_secret = os.getenv("BLACKANT_TEST_CLIENT_SECRET")
        self.login_url = os.getenv("BLACKANT_LOGIN_URL", "http://localhost/api/auth/login")

        if not self.client_id or not self.client_secret:
            self.skipTest(
                "BLACKANT_TEST_CLIENT_ID and BLACKANT_TEST_CLIENT_SECRET not set. "
                "Skipping client credentials tests."
            )

    def test_client_credentials_authentication(self):
        """Test client credentials authentication flow."""
        auth = BlackAntAuth(
            client_id=self.client_id,
            client_secret=self.client_secret,
            login_url=self.login_url
        )

        # Verify auth mode is client_credentials
        self.assertEqual(auth._auth_mode, "client_credentials")

        # Authenticate
        token = auth.authenticate()

        # Verify token
        self.assertIsInstance(token, str)
        self.assertNotEqual(token, "")
        self.assertTrue(len(token) > 20)  # Should be a JWT or similar

        # Verify authenticated status
        self.assertTrue(auth.is_authenticated())
        self.assertEqual(auth.token_store.user_token, token)

    def test_client_credentials_get_token(self):
        """Test get_token() with client credentials."""
        auth = BlackAntAuth(
            client_id=self.client_id,
            client_secret=self.client_secret,
            login_url=self.login_url
        )

        # Should authenticate automatically
        token = auth.get_token()

        self.assertIsInstance(token, str)
        self.assertTrue(auth.is_authenticated())

    def test_client_credentials_blackant_client(self):
        """Test BlackAntClient initialization with client credentials."""
        client = BlackAntClient(
            client_id=self.client_id,
            client_secret=self.client_secret,
            login_url=self.login_url
        )

        # Verify client is initialized correctly
        self.assertIsNotNone(client.auth)
        self.assertEqual(client.auth._auth_mode, "client_credentials")

        # Test authentication
        result = client.authenticate()
        self.assertTrue(result)
        self.assertTrue(client.is_authenticated())

    def test_client_credentials_connection_test(self):
        """Test connection test with client credentials."""
        client = BlackAntClient(
            client_id=self.client_id,
            client_secret=self.client_secret,
            login_url=self.login_url
        )

        # Test connection should authenticate and verify services
        try:
            result = client.test_connection()
            # May fail if services are not available, but authentication should work
            # We mainly care that it doesn't raise authentication errors
            self.assertIsInstance(result, bool)
        except Exception as e:
            # If it fails, it should not be an authentication error
            self.assertNotIsInstance(e, BlackAntAuthenticationError)

    def test_invalid_client_credentials(self):
        """Test that invalid client credentials raise proper error."""
        auth = BlackAntAuth(
            client_id="invalid-client-id",
            client_secret="invalid-secret",
            login_url=self.login_url
        )

        with self.assertRaises(BlackAntAuthenticationError):
            auth.authenticate()

    def test_client_credentials_logout(self):
        """Test logout with client credentials."""
        auth = BlackAntAuth(
            client_id=self.client_id,
            client_secret=self.client_secret,
            login_url=self.login_url
        )

        # Authenticate first
        auth.authenticate()
        self.assertTrue(auth.is_authenticated())

        # Logout
        auth.logout()
        self.assertFalse(auth.is_authenticated())
        self.assertIsNone(auth.token_store.user_token)


class TestClientCredentialsVsPasswordFlow(unittest.TestCase):
    """Test comparing client credentials vs password flow."""

    def setUp(self):
        """Set up test environment."""
        # Check if we have both credentials
        self.client_id = os.getenv("BLACKANT_TEST_CLIENT_ID")
        self.client_secret = os.getenv("BLACKANT_TEST_CLIENT_SECRET")
        self.test_user = os.getenv("BLACKANT_TEST_USER", "admin")
        self.test_password = os.getenv("BLACKANT_TEST_PASSWORD")
        self.login_url = os.getenv("BLACKANT_LOGIN_URL", "http://localhost/api/auth/login")

        if not self.client_id or not self.client_secret:
            self.skipTest("Client credentials not available")

        if not self.test_password:
            self.skipTest("Password credentials not available")

    def test_both_flows_work(self):
        """Test that both authentication flows work independently."""
        # Password flow
        auth_password = BlackAntAuth(
            user=self.test_user,
            password=self.test_password,
            login_url=self.login_url
        )
        token_password = auth_password.authenticate()
        self.assertIsInstance(token_password, str)
        self.assertEqual(auth_password._auth_mode, "password")

        # Client credentials flow
        auth_client = BlackAntAuth(
            client_id=self.client_id,
            client_secret=self.client_secret,
            login_url=self.login_url
        )
        token_client = auth_client.authenticate()
        self.assertIsInstance(token_client, str)
        self.assertEqual(auth_client._auth_mode, "client_credentials")

        # Both should be authenticated
        self.assertTrue(auth_password.is_authenticated())
        self.assertTrue(auth_client.is_authenticated())


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