# 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 typing import Mapping

from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.data_classes.api_gateway_proxy_event import APIGatewayProxyEvent
from voluptuous import ALLOW_EXTRA, All, Coerce, Range, Schema
from czc.string import vacuum_pack, vacuum_unpack

from czc.api.v2.constants import LIMIT_PARAMETER, OFFSET_PARAMETER, CURSOR_PARAMETER
from czc.api.v2.exceptions import APIErrorCode, BadRequestError

logger = Logger()


PAGINATION_PARAMETERS_SCHEMA = Schema({
    LIMIT_PARAMETER: All(Coerce(int), Range(1)),
    OFFSET_PARAMETER: All(Coerce(int), Range(0))
}, extra=ALLOW_EXTRA)


def pagination_parameters_schema():
    return PAGINATION_PARAMETERS_SCHEMA


def _format_cursor(unpacked_cursor):
    return vacuum_pack(unpacked_cursor).decode('utf-8')  # type: ignore


def limit_offset_cursors(unpacked_current_cursor, total_count):
    limit = unpacked_current_cursor[LIMIT_PARAMETER]
    offset = unpacked_current_cursor[OFFSET_PARAMETER]

    next_offset = offset + limit
    previous_offset = offset - limit

    next_cursor = _format_cursor({
        **unpacked_current_cursor,
        OFFSET_PARAMETER: next_offset
    }) if next_offset < total_count else None

    previous_cursor = _format_cursor({
        **unpacked_current_cursor,
        OFFSET_PARAMETER: previous_offset
    }) if previous_offset >= 0 else None

    logger.debug(f'previous cursor {previous_cursor} and next cursor {next_cursor}')
    return (previous_cursor, next_cursor)


def pagination_response(total_count, current_count, limit, previous_cursor, next_cursor):
    return {
        'pagination': {
            'page_count': int((total_count + (limit - 1)) / limit) if total_count > 0 else 0,
            'item_count': current_count,
            'total_count': total_count,
            CURSOR_PARAMETER: {
                'next_cursor': next_cursor,
                'previous_cursor': previous_cursor,
                'has_next': next_cursor is not None,
                'has_previous': previous_cursor is not None
            },
        }
    }


def unpack_cursor(event: APIGatewayProxyEvent) -> Mapping:
    cursor = event.get_query_string_value(CURSOR_PARAMETER)
    if not cursor:
        return {}
    try:
        return vacuum_unpack(cursor)
    except Exception as exc:
        logger.error(f'Invalid cursor: {exc}')
        raise BadRequestError(message='Invalid pagination cursor; did you urlencode it?', code=APIErrorCode.INVALID_PAGINATION)
