"""authentik OAuth2 Provider Forms"""

from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _

from authentik.admin.fields import CodeMirrorWidget
from authentik.core.expression import PropertyMappingEvaluator
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow, FlowDesignation
from authentik.providers.oauth2.generators import (
    generate_client_id,
    generate_client_secret,
)
from authentik.providers.oauth2.models import (
    JWTAlgorithms,
    OAuth2Provider,
    ScopeMapping,
)


class OAuth2ProviderForm(forms.ModelForm):
    """OAuth2 Provider form"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["authorization_flow"].queryset = Flow.objects.filter(
            designation=FlowDesignation.AUTHORIZATION
        )
        self.fields["client_id"].initial = generate_client_id()
        self.fields["client_secret"].initial = generate_client_secret()
        self.fields["rsa_key"].queryset = CertificateKeyPair.objects.exclude(
            key_data__exact=""
        )
        self.fields["property_mappings"].queryset = ScopeMapping.objects.all()

    def clean_jwt_alg(self):
        """Ensure that when RS256 is selected, a certificate-key-pair is selected"""
        if (
            self.data["rsa_key"] == ""
            and self.cleaned_data["jwt_alg"] == JWTAlgorithms.RS256
        ):
            raise ValidationError(
                _("RS256 requires a Certificate-Key-Pair to be selected.")
            )
        return self.cleaned_data["jwt_alg"]

    class Meta:
        model = OAuth2Provider
        fields = [
            "name",
            "authorization_flow",
            "client_type",
            "client_id",
            "client_secret",
            "token_validity",
            "jwt_alg",
            "property_mappings",
            "rsa_key",
            "redirect_uris",
            "sub_mode",
            "include_claims_in_id_token",
            "issuer_mode",
        ]
        widgets = {
            "name": forms.TextInput(),
            "token_validity": forms.TextInput(),
        }
        labels = {"property_mappings": _("Scopes")}
        help_texts = {
            "property_mappings": _(
                (
                    "Select which scopes <b>can</b> be used by the client. "
                    "The client stil has to specify the scope to access the data."
                )
            )
        }


class ScopeMappingForm(forms.ModelForm):
    """Form to edit ScopeMappings"""

    template_name = "providers/oauth2/property_mapping_form.html"

    def clean_expression(self):
        """Test Syntax"""
        expression = self.cleaned_data.get("expression")
        evaluator = PropertyMappingEvaluator()
        evaluator.validate(expression)
        return expression

    class Meta:

        model = ScopeMapping
        fields = ["name", "scope_name", "description", "expression"]
        widgets = {
            "name": forms.TextInput(),
            "scope_name": forms.TextInput(),
            "description": forms.TextInput(),
            "expression": CodeMirrorWidget(mode="python"),
        }
