# 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 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)
