#
#   Copyright © 2021,2022 IsardVDI S.L.
#
#   This file is part of DD
#
#   DD is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or (at your
#   option) any later version.
#
#   DD is distributed in the hope that it will be useful, but WITHOUT ANY
#   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#   FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
#   details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later

import json
import logging as log
import os
import os.path

from admin.lib.keycloak_client import KeycloakClient


class KeycloakConfig:
    def __init__(self):
        self.keycloak = KeycloakClient()
        self.domain = os.getenv('DOMAIN', 'localhost')

    def config_realm_update(self, path_json="/admin/custom/keycloak/realm.json"):
        self.keycloak.connect()
        k = self.keycloak.keycloak_admin
        path = path_json if os.path.isfile(path_json) else '/admin/keycloak-init/realm.json'
        with open(path) as json_file:
            json_body = json_file.read().replace('DDDOMAIN', self.domain)
            d_update = json.loads(json_body)
            k.update_realm("master", d_update)

    def config_role_list(self):
        self.keycloak.connect()
        k = self.keycloak.keycloak_admin

        name_protocol_mapper = "role list"
        id_client_scope_role_list = [
            a["id"] for a in k.get_client_scopes() if a["name"] == "role_list"
        ][0]
        d = k.get_client_scope(id_client_scope_role_list)
        d_mapper = [
            a for a in d["protocolMappers"] if a["name"] == name_protocol_mapper
        ][0]
        id_mapper = d_mapper["id"]

        # Single Role Attribute = On
        d_mapper["config"]["single"] = "true"

        k.update_mapper_in_client_scope(id_client_scope_role_list, id_mapper, d_mapper)

    def get_client(self, client_name):
        self.keycloak.connect()
        k = self.keycloak.keycloak_admin

        clients = k.get_clients()
        client = next(filter(lambda c: c["clientId"] == client_name, clients))
        return (k, client)

    def config_client(self, client_name):
        (k, client) = self.get_client(client_name)
        client_id = client["id"]

        client_overrides = {
            "redirectUris": [
                "/realms/master/account/*",
                f"https://moodle.{self.domain}/*",
                f"https://nextcloud.{self.domain}/*",
                f"https://wp.{self.domain}/*",
            ],
        }

        k.update_client(client_id, client_overrides)

    def set_client_mapper(self, client_name, mapper_name, script):
        (k, client) = self.get_client(client_name)
        pms = client["protocolMappers"]
        if mapper_name in [pm["name"] for pm in pms]:
            # It exists, update
            mapper_id = next(filter(lambda pm: pm["name"] == mapper_name, pms))["id"]
            set_mapper = lambda pl: k.update_client_mapper(client["id"], mapper_id, pl)
        else:
            # It does not exist, create
            set_mapper = lambda pl: k.add_mapper_to_client(client["id"], pl)

        mapper = {
            "name": mapper_name,
            "protocol": "saml",
            "protocolMapper": "saml-javascript-mapper",
            "consentRequired": "false",
            "config": {
                "single": "true",
                "Script": script,
                "attribute.nameformat": "Basic",
                "friendly.name": mapper_name,
                "attribute.name": mapper_name,
            },
        }

        set_mapper(mapper)


if __name__ == "__main__":
    keycloak_config = KeycloakConfig()
    print("Provisioning realm")
    keycloak_config.config_realm_update()
    print("Provisioning role list")
    keycloak_config.config_role_list()
    for client_name in [ "account", "account-console" ]:
        print(f"Provisioning client '{client_name}'")
        keycloak_config.config_client(client_name)
