#
#   Copyright © 2021,2022 IsardVDI S.L.
#   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
# Copyright 2017 the Isard-vdi project authors:
#      Josep Maria Viñolas Auquer
#      Alberto Larraz Dalmases
# License: AGPLv3

import json
import logging as log
import os
import traceback
from functools import wraps

from flask import request
from jose import jwt
import jose.exceptions

from typing import Any

from admin.lib.api_exceptions import Error


def get_header_jwt_payload() -> Any:
    return get_token_payload(get_token_auth_header())


def get_token_header(header : str) -> str:
    """Obtains the Access Token from the a Header"""
    auth = request.headers.get(header, None)
    if not auth:
        raise Error(
            "unauthorized",
            "Authorization header is expected",
            traceback.format_stack(),
        )

    parts = auth.split()
    if parts[0].lower() != "bearer":
        raise Error(
            "unauthorized",
            "Authorization header must start with Bearer",
            traceback.format_stack(),
        )

    elif len(parts) == 1:
        raise Error("bad_request", "Token not found")
    elif len(parts) > 2:
        raise Error(
            "unauthorized",
            "Authorization header must be Bearer token",
            traceback.format_stack(),
        )

    return parts[1]  # Token


def get_token_auth_header() -> str:
    return get_token_header("Authorization")


def get_token_payload(token : str) -> Any:
    # log.warning("The received token in get_token_payload is: " + str(token))
    try:
        claims = jwt.get_unverified_claims(token)
        secret = os.environ["API_SECRET"]

    except:
        log.warning(
            "JWT token with invalid parameters. Can not parse it.: " + str(token)
        )
        raise Error(
            "unauthorized",
            "Unable to parse authentication parameters token.",
            traceback.format_stack(),
        )

    try:
        payload = jwt.decode(
            token,
            secret,
            algorithms=["HS256"],
            options=dict(verify_aud=False, verify_sub=False, verify_exp=True),
        )
    except jose.exceptions.ExpiredSignatureError:
        log.warning("Token expired")
        raise Error("unauthorized", "Token is expired", traceback.format_stack())

    except jose.exceptions.JWTClaimsError:
        raise Error(
            "unauthorized",
            "Incorrect claims, please check the audience and issuer",
            traceback.format_stack(),
        )
    except Exception:
        raise Error(
            "unauthorized",
            "Unable to parse authentication token.",
            traceback.format_stack(),
        )
    if payload.get("data", False):
        return payload["data"]
    return payload
