import datetime
import json
import six
import uuid
from django.db import models
from django.apps import apps
from django.http import JsonResponse

from gm_types.utils.enum import EnumMeta

def schema_api(request):
    app_label = request.GET.get('app_label')
    db_table = request.GET.get('db_table')
    data = schema_view(app_label, db_table)
    return JsonResponse(data, safe=False)

def schema_view(app_label=None, db_table=None):
    """retrieve model schema
    """
    modelCls = get_models(app_label, db_table)

    schemas = []
    for model in modelCls:
        schema = {
            "app_label": model._meta.app_label,
            "db_table": model._meta.db_table,
            "fields": [],
        }
        for field in model._meta.get_fields():
            if not field.concrete:
                continue

            if field.default is models.fields.NOT_PROVIDED:
                default = "NOT_PROVIDED"
            elif isinstance(field.default, datetime.datetime):
                default = field.default.strftime("%Y-%m-%d %H:%M:%S")
            elif isinstance(field.default, datetime.time):
                default = field.default.strftime("%H:%M:%S")
            elif type(field.default) == type(uuid.uuid4):
                default = field.default.__name__.upper()
            else:
                try:
                    json.dumps(field.default)
                    default = field.default
                except TypeError:
                    default = "NOT_SERIALIZABLE"

            if type(field.choices) == EnumMeta:
                choices = [v for v in field.choices]
            else:
                choices = field.choices

            schema["fields"].append({
                "name": field.name,
                "null": field.null,
                "blank": field.blank,
                "choices": choices,
                "db_column": field.db_column,
                "db_index": field.db_index,
                "db_tablespace": field.db_tablespace,
                "default": default,
                "unique": field.unique,
                "primary_key": field.primary_key,
                "verbose_name": field.verbose_name if isinstance(field.verbose_name, six.string_types) else "",
                "help_text": field.help_text if isinstance(field.help_text, six.string_types) else "",
            })
        schemas.append(schema)
    return schemas


def get_models(app_label=None, db_table=None):
    try:
        mCls = models.get_models()

        if app_label:
            f = lambda m: m._meta.app_label == app_label
            mCls = filter(f, mCls)
    except AttributeError:
        if app_label:
            mDict = apps.all_models[app_label]
            mCls = mDict.values()
        else:
            mCls = []
            for app in apps.all_models:
                mCls.extend(list(apps.all_models[app].values()))

    if db_table:
        f = lambda m: m._meta.db_table == db_table
        mCls = filter(f, mCls)
    return mCls
