# -*- coding: utf-8 -*-

from .grammar import QueryGrammar


class PostgresQueryGrammar(QueryGrammar):

    _operators = [
        '=', '<', '>', '<=', '>=', '<>', '!=',
        'like', 'not like', 'between', 'ilike',
        '&', '|', '#', '<<', '>>'
    ]

    marker = '%s'

    def _compile_lock(self, query, value):
        """
        Compile the lock into SQL

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :param value: The lock value
        :type value: bool or str

        :return: The compiled lock
        :rtype: str
        """
        if isinstance(value, str):
            return value

        if value:
            return 'FOR UPDATE'

        return 'FOR SHARE'

    def compile_update(self, query, values):
        """
        Compile an update statement into SQL

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :param values: The update values
        :type values: dict

        :return: The compiled update
        :rtype: str
        """
        table = self.wrap_table(query.from__)

        columns = self._compile_update_columns(values)

        from_ = self._compile_update_from(query)

        where = self._compile_update_wheres(query)

        return ('UPDATE %s SET %s%s %s' %
                (table, columns, from_, where)).strip()

    def _compile_update_columns(self, values):
        """
        Compile the columns for the update statement

        :param values: The columns
        :type values: dict

        :return: The compiled columns
        :rtype: str
        """
        columns = []

        for key, value in values.items():
            columns.append('%s = %s' % (self.wrap(key), self.parameter(value)))

        return ', '.join(columns)

    def _compile_update_from(self, query):
        """
        Compile the "from" clause for an update with a join.

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :return: The compiled sql
        :rtype: str
        """
        if not query.joins:
            return ''

        froms = []

        for join in query.joins:
            froms.append(self.wrap_table(join.table))

        if len(froms):
            return ' FROM %s' % ', '.join(froms)

        return ''

    def _compile_update_wheres(self, query):
        """
        Compile the additional where clauses for updates with joins.

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :return: The compiled sql
        :rtype: str
        """
        base_where = self._compile_wheres(query)

        if not query.joins:
            return base_where

        join_where = self._compile_update_join_wheres(query)

        if not base_where.strip():
            return 'WHERE %s' % self._remove_leading_boolean(join_where)

        return '%s %s' % (base_where, join_where)

    def _compile_update_join_wheres(self, query):
        """
        Compile the "join" clauses for an update.

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :return: The compiled sql
        :rtype: str
        """
        join_wheres = []

        for join in query.joins:
            for clause in join.clauses:
                join_wheres.append(self._compile_join_constraints(clause))

        return ' '.join(join_wheres)

    def compile_insert_get_id(self, query, values, sequence=None):
        """
        Compile an insert and get ID statement into SQL.

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :param values: The values to insert
        :type values: dict

        :param sequence: The id sequence
        :type sequence: str

        :return: The compiled statement
        :rtype: str
        """
        if sequence is None:
            sequence = 'id'

        return '%s RETURNING %s'\
               % (self.compile_insert(query, values), self.wrap(sequence))

    def compile_truncate(self, query):
        """
        Compile a truncate table statement into SQL.

        :param query: A QueryBuilder instance
        :type query: QueryBuilder

        :return: The compiled statement
        :rtype: str
        """
        return {
            'TRUNCATE %s RESTART IDENTITY' % self.wrap_table(query.from__): {}
        }
