#!/usr/bin/env python3
"""
Script pour corriger la configuration du client Keycloak
"""

import requests
import json
import time

class ClientFixer:
    def __init__(self, base_url: str = "http://localhost:8180"):
        self.base_url = base_url
        self.session = requests.Session()
        self.admin_token = None
        
    def get_admin_token(self) -> bool:
        """Obtient le token admin"""
        try:
            data = {
                "username": "admin",
                "password": "admin",
                "grant_type": "password",
                "client_id": "admin-cli"
            }
            
            response = self.session.post(
                f"{self.base_url}/realms/master/protocol/openid-connect/token",
                data=data,
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            )
            
            if response.status_code == 200:
                token_data = response.json()
                self.admin_token = token_data.get("access_token")
                return self.admin_token is not None
                
        except Exception as e:
            print(f"Erreur obtention token: {e}")
            
        return False
    
    def get_client_id(self, realm_name: str, client_id: str) -> str:
        """Obtient l'ID interne du client"""
        try:
            response = self.session.get(
                f"{self.base_url}/admin/realms/{realm_name}/clients",
                headers={"Authorization": f"Bearer {self.admin_token}"}
            )
            
            if response.status_code == 200:
                clients = response.json()
                for client in clients:
                    if client.get("clientId") == client_id:
                        return client.get("id")
            
        except Exception as e:
            print(f"Erreur récupération client ID: {e}")
            
        return None
    
    def delete_client_if_exists(self, realm_name: str, client_id: str) -> bool:
        """Supprime le client s'il existe"""
        internal_id = self.get_client_id(realm_name, client_id)
        if internal_id:
            try:
                response = self.session.delete(
                    f"{self.base_url}/admin/realms/{realm_name}/clients/{internal_id}",
                    headers={"Authorization": f"Bearer {self.admin_token}"}
                )
                if response.status_code == 204:
                    print(f"   ✓ Client {client_id} supprimé")
                    return True
            except Exception as e:
                print(f"   ⚠ Erreur suppression client: {e}")
        
        return False
    
    def create_client_complete(self, realm_name: str = "unionflow", client_id: str = "unionflow-mobile") -> bool:
        """Crée le client avec la configuration complète"""
        print(f"🔧 Création complète du client {client_id}...")
        
        # 1. Supprimer s'il existe
        self.delete_client_if_exists(realm_name, client_id)
        
        # 2. Créer le client avec une configuration complète
        client_data = {
            "clientId": client_id,
            "name": "UnionFlow Mobile App",
            "description": "Client pour l'application mobile UnionFlow",
            "enabled": True,
            "clientAuthenticatorType": "client-secret",
            "secret": "",
            "redirectUris": ["*"],
            "webOrigins": ["*"],
            "notBefore": 0,
            "bearerOnly": False,
            "consentRequired": False,
            "standardFlowEnabled": True,
            "implicitFlowEnabled": False,
            "directAccessGrantsEnabled": True,
            "serviceAccountsEnabled": False,
            "publicClient": True,
            "frontchannelLogout": False,
            "protocol": "openid-connect",
            "attributes": {
                "saml.assertion.signature": "false",
                "saml.force.post.binding": "false",
                "saml.multivalued.roles": "false",
                "saml.encrypt": "false",
                "saml.server.signature": "false",
                "saml.server.signature.keyinfo.ext": "false",
                "exclude.session.state.from.auth.response": "false",
                "saml_force_name_id_format": "false",
                "saml.client.signature": "false",
                "tls.client.certificate.bound.access.tokens": "false",
                "saml.authnstatement": "false",
                "display.on.consent.screen": "false",
                "saml.onetimeuse.condition": "false",
                "access.token.lifespan": "300",
                "client_credentials.use_refresh_token": "false"
            },
            "authenticationFlowBindingOverrides": {},
            "fullScopeAllowed": True,
            "nodeReRegistrationTimeout": -1,
            "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"],
            "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"]
        }
        
        try:
            response = self.session.post(
                f"{self.base_url}/admin/realms/{realm_name}/clients",
                json=client_data,
                headers={
                    "Authorization": f"Bearer {self.admin_token}",
                    "Content-Type": "application/json"
                }
            )
            
            if response.status_code == 201:
                print(f"   ✓ Client {client_id} créé avec succès")
                
                # Attendre un peu pour que la configuration soit prise en compte
                time.sleep(2)
                
                # Vérifier la configuration
                internal_id = self.get_client_id(realm_name, client_id)
                if internal_id:
                    # Récupérer la configuration du client
                    get_response = self.session.get(
                        f"{self.base_url}/admin/realms/{realm_name}/clients/{internal_id}",
                        headers={"Authorization": f"Bearer {self.admin_token}"}
                    )
                    
                    if get_response.status_code == 200:
                        client_config = get_response.json()
                        print(f"   ✓ Configuration vérifiée:")
                        print(f"     - Public Client: {client_config.get('publicClient')}")
                        print(f"     - Direct Access Grants: {client_config.get('directAccessGrantsEnabled')}")
                        print(f"     - Standard Flow: {client_config.get('standardFlowEnabled')}")
                        print(f"     - Enabled: {client_config.get('enabled')}")
                        
                        return True
                
            else:
                print(f"   ✗ Erreur création client: {response.status_code}")
                print(f"       Réponse: {response.text}")
                return False
                
        except Exception as e:
            print(f"   ✗ Exception création client: {e}")
            return False
    
    def test_client_auth(self, realm_name: str = "unionflow", client_id: str = "unionflow-mobile") -> bool:
        """Teste l'authentification avec le client"""
        print(f"🧪 Test d'authentification avec le client...")
        
        # Attendre un peu pour que tout soit synchronisé
        time.sleep(3)
        
        test_data = {
            "username": "marie.active",
            "password": "Marie123!",
            "grant_type": "password",
            "client_id": client_id
        }
        
        try:
            response = self.session.post(
                f"{self.base_url}/realms/{realm_name}/protocol/openid-connect/token",
                data=test_data,
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            )
            
            print(f"   Status: {response.status_code}")
            
            if response.status_code == 200:
                token_data = response.json()
                if "access_token" in token_data:
                    print(f"   ✅ AUTHENTIFICATION RÉUSSIE !")
                    print(f"   ✓ Token reçu (longueur: {len(token_data['access_token'])})")
                    return True
                else:
                    print(f"   ❌ Token manquant dans la réponse")
            else:
                print(f"   ❌ Authentification échouée")
                print(f"       Réponse: {response.text}")
            
        except Exception as e:
            print(f"   ❌ Exception test auth: {e}")
        
        return False
    
    def fix_complete(self):
        """Correction complète du client"""
        print("=" * 80)
        print("🔧 CORRECTION DU CLIENT KEYCLOAK")
        print("=" * 80)
        print()
        
        if not self.get_admin_token():
            print("❌ Impossible d'obtenir le token admin")
            return False
        
        print("✅ Token admin obtenu")
        print()
        
        # Créer le client
        if not self.create_client_complete():
            print("❌ Échec de la création du client")
            return False
        
        print()
        
        # Tester l'authentification
        if self.test_client_auth():
            print()
            print("=" * 80)
            print("🎉 CLIENT CORRIGÉ AVEC SUCCÈS !")
            print("=" * 80)
            print()
            print("🚀 Maintenant testez tous les comptes avec: python test_auth.py")
            return True
        else:
            print()
            print("=" * 80)
            print("⚠️ CLIENT CRÉÉ MAIS PROBLÈME D'AUTHENTIFICATION")
            print("=" * 80)
            return False


def main():
    fixer = ClientFixer()
    fixer.fix_complete()


if __name__ == "__main__":
    main()
