from datetime import date
from graphql import GraphQLError
from graphql.type.definition import GraphQLObjectType
from ariadne.types import GraphQLResolveInfo
from sqlalchemy import select
from sqlalchemy.orm import Session

from .starlettebackend import User


nulldate = date(1753, 1, 1)


def parse_date(datep, fieldname: str = 'Date'):
    try:
        return date.fromisoformat(datep)
    except ValueError:
        raise GraphQLError(f'{fieldname} does not have correct format (YYYY-MM-DD)')


def get_dbsession(info) -> Session:
    return info.context['request'].state.dbsession


def get_user(info: GraphQLResolveInfo) -> User:
    return info.context['request'].user


def get_all_records(info, q):
    return get_dbsession(info).execute(q).scalars().unique().all()  # Todo: Watch out for that .unique()


def get_one_record(info, q):
    return get_dbsession(info).execute(q).scalars().first()


def get_one_field(info, q):
    return get_dbsession(info).execute(q).scalar()


def simple_table_resolver_factory(model, query_modifiers=None):
    def simple_table_resolver(_, info, filters, limit, offset):
        q = select(model)
        if filters is not None:
            for f in filters:
                q = q.where(getattr(model, f['field']).like(f['value']))

        if query_modifiers is not None:
            q = query_modifiers(q)

        q = q.limit(limit).offset(offset)

        return get_all_records(info, q)
    return simple_table_resolver


def resolve_type_inspector(_, info: GraphQLResolveInfo, type_name):
    gqltype = info.schema.get_type(type_name)
    if gqltype is None or not isinstance(gqltype, GraphQLObjectType):
        return None

    result = {
        'filter_fields': [],
        'edit_fields': []
    }

    all_filter = hasattr(gqltype, '__all_filter__')

    for field_name, field in gqltype.fields.items():
        if hasattr(field, '__filter__'):
            if getattr(field, '__filter__'):
                result['filter_fields'].append(field_name)
        elif all_filter:
            result['filter_fields'].append(field_name)

    return result
