import copy
from .update_mode import UpdateMode
from genson import SchemaBuilder  # type: ignore


def _to_openapi_compatible(schema):
    """OpenAPI does not strictly use JSON schema so convert to the OpenAPI subset.

    https://swagger.io/docs/specification/data-models/keywords/

    Arguments:
        schema -- Schema

    Returns:
        Modified schema
    """
    schema = copy.deepcopy(schema)
    if '$schema' in schema:
        del schema['$schema']
    return schema

def to_const(obj):
    if type(obj) == type(''):
        return { 'type': 'string', 'enum': [obj] }
    if type(obj) == type(0):
        return { 'type': 'integer', 'enum': [obj] }
    if type(obj) == type(0.0):
        return { 'type': 'number', 'enum': [obj] }
    if obj is None:
        return { 'type': 'null' }
    if type(obj) == type(True):
        return { 'type': 'boolean', 'enum': [obj] }
    if type(obj) == type([]):
        return { 'type': 'array', 'items': [to_const(x) for x in obj] }
    return {
        'type': 'object',
        'properties': { k: to_const(v) for k, v in obj.items() },
        'required': [x for x in obj.keys()]
    }


def to_json_schema(obj, mode: UpdateMode, schema=None):
    """Create JSON schema based on an object.

    Arguments:
        obj {dict} -- Dictionary object

    Keyword Arguments:
        schema {dict} -- Existing schema if exists. (default: {None})

    Returns:
        [dict] -- New or updated schema.
    """
    if mode == UpdateMode.GEN:
        builder = SchemaBuilder()
        if schema is not None:
            builder.add_schema(schema)
        builder.add_object(obj)
        schema = builder.to_schema()
        return schema
    elif schema is None:
        return { 'oneOf': [to_const(obj)] }
    else:
        return { 'oneOf': [to_const(obj), schema]}



def to_openapi_json_schema(obj, mode: UpdateMode, schema=None):
    """Create OpenAPI-compatible JSON schema from object.

    https://swagger.io/docs/specification/data-models/keywords/

    Arguments:
        obj {[type]} -- [description]

    Keyword Arguments:
        schema {[type]} -- [description] (default: {None})

    Returns:
        [type] -- [description]
    """
    schema = to_json_schema(obj, mode, schema)
    openapi_compatible_schema = _to_openapi_compatible(schema)
    return openapi_compatible_schema
