# Copyright (c) 2021 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com

from collections.abc import Mapping
from typing import Optional

from aws_lambda_powertools import Tracer
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent
from aws_lambda_powertools.utilities.idempotency.persistence.dynamodb import DynamoDBPersistenceLayer
from voluptuous import Schema

from czc.api.v2.caching import cache_header_aware
from czc.api.v2.gateway import authorization_context, coerce_event, coerce_response, parameters, serialize_response
from czc.api.v2.idempotency import idempotency_key_aware
from czc.api.v2.testing import test_key_aware
from czc.logging import Logger, get_logger, get_tracer, log_context_from_event

default_logger = get_logger()
default_tracer = get_tracer()


def api(
    default_error_message: str = 'API Error',
    persistence_store: DynamoDBPersistenceLayer = None,
    authorization_schema: Schema = None,
    event_schema: Schema = None,
    path_schema: Schema = None,
    query_schema: Schema = None,
    body_schema: Schema = None,
    multi_value_query_schema: Schema = None,
    tracer: Tracer = default_tracer,
    logger: Logger = default_logger,
    logger_event_jmespaths: Optional[dict[str, str]] = None,
    logger_response_jmespaths: Optional[dict[str, str]] = None,
):
    """Make this Lambda Handler V2 Compliant by composing all necessary decorators

    Parameters
    ----------
    default_error_message: str, optional
        passed to @request_response(default_error_message=default_error_message)
    persistence_store: DynamoDBPersistenceLayer, optional
        passed to @idempotency_key_aware(persistence_store=persistence_store)
    authorization_schema: Schema, optional
        passed to @authorization_context(schema=authorization_schema)
    event_schema: Schema, optional
        passed to @parameters(event_schema=event_schema)
    path_schema: Schema, optional
        passed to @parameters(path_schema=path_schema)
    query_schema: Schema, optional
        passed to @parameters(query_schema=query_schema
    body_schema: Schema, optional
        passed to @parameters(body_schema=body_schema
    multi_value_query_schema: Schema, optional
        passed to @parameters(query_schema=query_schema
    Returns
    -------
    Callable
        Decorated Lambda Handler
    """

    def decorator(handler):
        @log_context_from_event(
            logger=logger, event_jmespaths=logger_event_jmespaths, response_jmespaths=logger_response_jmespaths
        )
        @tracer.capture_lambda_handler
        @logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
        @coerce_event()
        @idempotency_key_aware(persistence_store=persistence_store)
        @test_key_aware()
        @serialize_response(default_error_message=default_error_message)
        @cache_header_aware()
        @coerce_response()
        @authorization_context(schema=authorization_schema)
        @parameters(
            event_schema=event_schema,
            path_schema=path_schema,
            query_schema=query_schema,
            body_schema=body_schema,
            multi_value_query_schema=multi_value_query_schema,
        )
        def lambda_handler(event: APIGatewayProxyEvent, context, **kwargs) -> Mapping:
            return handler(event, context, **kwargs)

        return lambda_handler

    return decorator
