# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from sql import Expression, Literal, Null, Query
from sql.operators import ILike, In, Not, NotIn

from trytond.transaction import Transaction

from .char import Char
from .field import SQL_OPERATORS, Field, order_method


class Text(Char):
    '''
    Define a text field (``unicode``).
    '''
    _type = 'text'
    _sql_type = 'TEXT'
    forbidden_chars = ''
    search_full_text = True

    def __init__(self, *args, strip=False, **kwarg):
        super().__init__(*args, strip=strip, **kwarg)


class FullText(Field):
    '''
    Define a full text field.
    '''
    _type = 'full_text'
    _sql_type = 'FULLTEXT'
    _py_type = str

    def sql_format(self, value):
        if isinstance(value, (Query, Expression)):
            return value
        if not value:
            return Null
        if isinstance(value, (int, float)):
            return value
        transaction = Transaction()
        database = transaction.database
        if isinstance(value, str):
            value = [value]
        return database.format_full_text(*value, language=transaction.language)

    def _rank_column(self, column, name, Model):
        transaction = Transaction()
        context = transaction.context
        database = transaction.database
        key = '%s.%s.order' % (Model.__name__, name)
        value = context.get(key)
        if value and database.has_search_full_text():
            value = database.format_full_text_query(
                value, language=transaction.language)
            return database.rank_full_text(column, value, normalize=['rank'])

    def convert_domain(self, domain, tables, Model):
        transaction = Transaction()
        database = transaction.database
        table, _ = tables[None]
        name, operator, value = domain
        assert name == self.name
        column = self.sql_column(table)
        column = self._domain_column(operator, column)
        if operator.endswith('like'):
            if database.has_search_full_text():
                value = database.format_full_text_query(
                    value, language=transaction.language)
                expression = database.search_full_text(column, value)
            else:
                expression = Literal(True)
                for v in value.split():
                    expression &= ILike(column, '%' + v + '%')
            if operator.startswith('not'):
                expression = Not(expression)
        else:
            Operator = SQL_OPERATORS[operator]
            column = self._rank_column(column, name, Model)
            expression = Operator(column, self._domain_value(operator, value))
            if isinstance(expression, In) and not expression.right:
                expression = Literal(False)
            elif isinstance(expression, NotIn) and not expression.right:
                expression = Literal(True)
            expression = self._domain_add_null(
                column, operator, value, expression)
        return expression

    @order_method
    def convert_order(self, name, tables, Model):
        table, _ = tables[None]
        column = self.sql_column(table)
        column = self._domain_column('ilike', column)
        column = self._rank_column(column, name, Model)
        if column:
            return [column]
        return []
