#
#   Copyright © 2022 MaadiX
#   Copyright © 2022 Evilham <contact@evilham.com>
#
#   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 traceback
from operator import itemgetter
from typing import TYPE_CHECKING, Any, Dict, List, cast

from flask import request

from admin.auth.jws_tokens import has_jws_token
from admin.lib.callbacks import user_parser
from admin.views.decorators import JsonResponse

from ..lib.api_exceptions import Error

if TYPE_CHECKING:
    from admin.flaskapp import AdminFlaskApp

JsonHeaders = {"Content-Type": "application/json"}


def setup_mail_views(app: "AdminFlaskApp") -> None:
    mail_3p = app.api_3p["correu"]

    @app.json_route("/ddapi/pubkey", methods=["GET"])
    def pub_key() -> JsonResponse:
        key = json.dumps(mail_3p.our_pubkey_jwk)
        return key, 200, {"Content-Type": "application/json"}

    @app.route("/ddapi/mailusers", methods=["GET", "POST", "PUT"])
    @has_jws_token(app)
    def ddapi_mail_users() -> JsonResponse:
        users: List[Dict[str, Any]] = []
        if request.method == "GET":
            try:
                sorted_users = sorted(
                    app.admin.get_mix_users(), key=itemgetter("username")
                )
                for user in sorted_users:
                    users.append(user_parser(user))
                # Encrypt data with mail client public key
                enc = mail_3p.sign_and_encrypt_outgoing_json({"users": users})
                headers = mail_3p.get_outgoing_request_headers()
                headers.update(JsonHeaders)
                return enc, 200, headers
            except:
                raise Error(
                    "internal_server", "Failure sending users", traceback.format_exc()
                )
        if request.method not in ["POST", "PUT"]:
            # Unsupported method
            # Note we do not support DELETE as it is taken care of when the
            # full Nextcloud user is deleted.
            return json.dumps({}), 400, JsonHeaders

        try:
            dec_data = cast(
                Dict, mail_3p.verify_and_decrypt_incoming_json(request.get_data())
            )
            users = dec_data.pop("users")
            config = dec_data.pop("config", {})
            # TODO: fix these validators
            #for user in users:
            #    if not app.validators["mail"].validate(user):
            #        raise Error(
            #            "bad_request",
            #            "Data validation for mail failed: "
            #            + str(app.validators["mail"].errors),
            #            traceback.format_exc(),
            #        )
            res: Dict
            if request.method in ["POST", "PUT"]:
                res = app.admin.nextcloud_mail_set(users, config)
            return (
                json.dumps(res),
                200,
                {"Content-Type": "application/json"},
            )
        except Exception as e:
            raise Error(
                "internal_server",
                "Failure changing user emails",
                traceback.format_exc(),
            )
