# Copyright (c) 2022 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 datetime import datetime
from math import trunc
from typing import List

from dateutil.parser import parse
from dateutil.tz import tzutc
from voluptuous import (ALLOW_EXTRA, REMOVE_EXTRA, All, Any, Coerce, Length,
                        Maybe, Number, Optional, Range, Schema)

#################
# BASE DATA TYPES
#################
COST_TYPES = ['billed_cost', 'real_cost']
COST_TYPE = Any(*COST_TYPES)
CURRENCY = All(Number(yield_decimal=True), lambda x: x if trunc(x) == x else round(x, 4))
GRANULARITIES = ['daily', 'hourly', 'weekly', '30days', 'monthly']
GRANULARITY = Any(*GRANULARITIES)
MONTH = All(str, parse, lambda d: datetime(year=d.year, month=d.month,
                                           day=1, tzinfo=tzutc()).isoformat())
DAY = All(str, parse, lambda d: datetime(year=d.year, month=d.month,
                                         day=d.day, hour=0, tzinfo=tzutc()).isoformat())
NAME = All(str, Length(1))

#################
# SORTING
#################
SORT_KEYS = ['last_updated']
SORT_KEY = Any(*SORT_KEYS)
SORT_ORDERS = ['asc', 'desc']
SORT_ORDER = Any(*SORT_ORDERS)

#################
# FILTERING
#################
FILTERS = Schema({str: list}, extra=REMOVE_EXTRA)


#################
# PAGINATION
#################

def cursor_schema(sort_keys: List[str] = SORT_KEYS):
    return Schema({
        'sort_key': Any(*sort_keys),
        'sort_order': SORT_ORDER,
        'limit': All(Coerce(int), Range(1)),
        'offset': All(Coerce(int), Range(0)),
        Optional('filters', default={}): FILTERS
    }, required=True, extra=ALLOW_EXTRA)


CURSOR_RESPONSE = Schema({
    'next_cursor': Maybe(str),
    'previous_cursor': Maybe(str),
    'has_next': bool,
    'has_previous': bool
}, required=True, extra=ALLOW_EXTRA)

PAGINATION = Schema({
    'page_count': int,
    'item_count': int,
    'total_count': int,
    'cursor': CURSOR_RESPONSE
}, required=True, extra=ALLOW_EXTRA)


def paginated_response_schema(sort_keys: List[str] = SORT_KEYS):
    return Schema({
        'pagination': PAGINATION,
        'sorting': {
            'available': {
                'sort_keys': sort_keys,
                'sort_orders': SORT_ORDERS,
            },
            'current': [Schema({'sort_key': Any(*sort_keys), 'sort_order': SORT_ORDER}, required=True, extra=ALLOW_EXTRA)],
        },
        'filters': FILTERS,
        'total_count': int,
    }, required=True, extra=ALLOW_EXTRA)


#################
# ENTITY BUILDING BLOCKS
#################
WITH_ID = Schema({'id': str}, required=True, extra=REMOVE_EXTRA)
WITH_TIMESTAMPS = Schema({
    'created': Number(),
    'last_updated': Number(),
}, required=True, extra=REMOVE_EXTRA)
WITH_ID_TIMESTAMPS = WITH_ID.extend(WITH_TIMESTAMPS.schema)
