# -*- coding=utf-8 -*-

from enum import Enum


class DBOperatorEnum(Enum):
    EQUAL_TO = '='
    NOT_EQUAL_TO = '!='
    LIKE = 'LIKE'
    NOT_LIKE = 'NOT LIKE'
    IN = 'IN'
    GREATER_THAN = '>'
    LESS_THAN = '>'
    GREATER_THAN_OR_EQUAL_TO = '>='
    LESS_THAN_OR_EQUAL_TO = '>='
    POSIX = '~'


class DBAndOrEnum(Enum):
    AND = 'AND'
    OR = 'OR'


class DBConditionParamsTypeEnum(Enum):
    P = 0
    C = 1


__db_expression = {
    'field': {
        'concat': {
            'comma_lr': """CONCAT(',', %s, ',')"""
        },
        'cast': {
            'varchar': """CAST(%s AS VARCHAR)"""
        }
    },
    'params': {
        'like': {
            'lr': '%%%s%%',
            'comma_lr': '%%,%s,%%'
        },
        'in': ' (%s) '
    }
}

DBExpression = __db_expression


class DBConditionModel(object):

    field = ''
    field_expression = ''
    operator = DBOperatorEnum.EQUAL_TO
    params = None
    params_expression = ''
    params_type = DBConditionParamsTypeEnum.P
    params_brackets = False
    and_or = DBAndOrEnum.AND
    use_and_or = True
    inner_and_or = DBAndOrEnum.AND

    def __init__(self):
        pass

    def __init__(self, field='', field_expression='', operator=DBOperatorEnum.EQUAL_TO, params=None, params_expression='', params_type=DBConditionParamsTypeEnum.P, params_brackets=False, and_or=DBAndOrEnum.AND, use_and_or=True, inner_and_or=DBAndOrEnum.AND, use_inner_and_or=False):

        self.field = field
        self.field_expression = field_expression
        self.operator = operator
        # print('operator:', operator, type(operator), operator.value, type(operator.value))
        # print('self.operator:', self.operator, type(self.operator), self.operator.value, type(self.operator.value))
        self.params = params
        self.params_expression = params_expression
        self.params_type = params_type
        self.params_brackets = params_brackets
        self.and_or = and_or
        self.use_and_or = use_and_or
        self.use_inner_and_or = use_inner_and_or
        self.inner_and_or = inner_and_or


class DBConditionHelper(object):

    @staticmethod
    def get_in_condition(field, params, **kwargs):
        return DBConditionModel(
            field=field,
            params=params,
            params_brackets=True,
            operator=DBOperatorEnum.IN,
            **kwargs
        )

    @staticmethod
    def get_equal_condition(field, params):
        return DBConditionModel(
            field=field,
            params=params,
        )

    @staticmethod
    def get_like_lr_condition(field, params, has_comma=True, **kwargs):
        field_expression = ''
        params_expression = DBExpression['params']['like']['lr']
        if has_comma:
            field_expression = DBExpression['field']['concat']['comma_lr']
            params_expression = DBExpression['params']['like']['comma_lr']

        return DBConditionModel(
            field=field,
            field_expression=field_expression,
            operator=DBOperatorEnum.LIKE,
            params=params,
            params_expression=params_expression,
            **kwargs
        )

    @staticmethod
    def get_posix_condition(field, params, has_field_cast_varchar_exp=True, **kwargs):
        field_expression = ''
        if has_field_cast_varchar_exp:
            field_expression = DBExpression['field']['cast']['varchar']
        return DBConditionModel(
            field=field,
            field_expression=field_expression,
            operator=DBOperatorEnum.POSIX,
            params=params,
            **kwargs
        )



class BaseDBHelper(object):

    connect_string = ''
    cur = None
    params = None

    def __init__(self, connect_string, **params):
        self.connect_string = connect_string
        self.params = params

    def connect(self):
        pass


    def fetch_returning_id(self, sql, *params, **kw):
        pass

    def fetch_rowcount(self, sql, *params, **kw):
        def callback(cur):
            # print('cur:',cur)
            return cur.rowcount

        return self.execute_sql(sql, callback, *params, **kw)

    def fetch_one(self, sql, *params, **kw):
        def callback(cur):
            return cur.fetchone()

        return self.execute_sql(sql, callback, *params, **kw)

    def fetch_all(self, sql, *params, **kw):
        def callback(cur):
            return cur.fetchall()

        return self.execute_sql(sql, callback, *params, **kw)

    def execute_sql(self, sql, callback, *params, **kw):
        pass

    def callproc(self, proc_name, *params):
        pass
