from db.database import Database
import traceback
from logger_module.package_logger import print_log
from flask import request


class QueryBuilder:

    QUERY_DICT = {
        "select": "select {columns} from {table_name}",
        "insert": "insert into {table_name} {columns} values {values}",
        "update": "update {table_name} set "
    }

    def __init__(self):
        self.request_body = request.get_json

    def create_query(self, query_type, table, columns=None, insert_values=None, clause=None, ordering=None):
        clause_string, order_string, set_query, placeholder = '', '', '', ''
        data_values = ()
        if query_type == 'select':
            columns = ','.join(columns) if columns else '*'
        if insert_values and query_type == 'insert':
            columns = f"({', '.join(tuple(insert_values.keys()))})"
            from key_resolver import KeyResolver
            for value_item in insert_values.values():
                resolved_value = KeyResolver().resolve_key(value_item, self.request_body)
                data_values = data_values + (resolved_value.replace("\r", "") if isinstance(resolved_value, str) else resolved_value,)
            placeholder = '(' + '%s,' * (len(data_values)-1) + '%s)'
        base_query = self.QUERY_DICT.get(query_type).format(columns=columns, table_name=table, values=placeholder)
        if query_type == 'update':
            for cols, value in insert_values.items():
                from key_resolver import KeyResolver
                resolved_col_value = KeyResolver().resolve_key(value, self.request_body)
                data_values = data_values + (resolved_col_value.replace("\r", "") if isinstance(resolved_col_value, str) else resolved_col_value,)
                set_query = set_query + f"""{cols} = %s ,"""
                if cols == list(insert_values.keys())[-1]:
                    set_query = set_query.rstrip(',')
            base_query = base_query + set_query
        if clause:
            comparator = clause.get('valueOperator', '=')
            if clause.get('where'):
                clause_string = 'where'
                clause_list = clause.get('where')
                param_list = clause.get('queryParams')
                for idx in range(len(clause_list)):
                    logical_operator = '' if idx == 0 else clause.get('logicalOperator', '')
                    from key_resolver import KeyResolver
                    resolved_param = KeyResolver().resolve_key(param_list[idx], self.request_body)
                    data_values = data_values + (resolved_param.replace("\r", "") if isinstance(resolved_param, str) else resolved_param,)
                    clause_string = (clause_string + " " + logical_operator + " " + clause_list[
                        idx] + " " + comparator + " %s ")
        if ordering:
            order_string = 'order by ' + ordering.get('column') + ' ' + ordering.get('sorting')
        query = base_query + ' ' + clause_string + ' ' + order_string
        return query, data_values

    def create_raw_query(self, query, params):
        resolved_param = ()
        from key_resolver import KeyResolver
        for param_item in params:
            resolved_value = KeyResolver().resolve_key(param_item, self.request_body)
            resolved_param = resolved_param + (resolved_value.replace("\r", "") if isinstance(resolved_value, str) else resolved_value,)

        return query, resolved_param


class QueryExecution:

    @classmethod
    def fetch_result(cls, query, params=()):
        try:
            with Database(True) as db:
                db.execute(query, params)
                try:
                    result_set = db.fetchall()
                except Exception as e:
                    return True, db.lastrowid
            if len(result_set) == 1:
                return True, result_set[0]
            if db.lastrowid:
                return True, db.lastrowid
            return True, result_set
        except Exception as ex:
            print_log(str(ex))
            traceback.print_exc()

