from datetime import date, datetime
from decimal import Decimal

from .exceptions import FieldFilterException


_SORTABLE_TYPES = set(( bool, str, int, float, datetime, date, Decimal ))
_SORTABLE_TYPES_STR = (', ').join(x.__name__ for x in _SORTABLE_TYPES)


class Field:

  def __init__(self, *keys):
    self._keys = keys
    self._filter = {}
    self._limit = 2

  def _chain(self, operator, operand):
    if isinstance(operand, Field):
      raise FieldFilterException('Cannot compare two fields')
    if len(self._filter) >= self._limit:
      raise FieldFilterException(f'Cannot chain more than two comparisons')
    if operator in self._filter:
      raise FieldFilterException(f"Duplicate chained '{operator}' operators")
    self._filter[operator] = operand
    return self

  def _assert_sortable(self, operator, operand):
    if type(operand) not in _SORTABLE_TYPES:
      raise FieldFilterException(f"Can only use '{operator}' operator with the following types: {_SORTABLE_TYPES_STR}")

  def __lt__(self, operand):
    self._assert_sortable('<', operand)
    return self._chain('<', operand)

  def __le__(self, operand):
    self._assert_sortable('<=', operand)
    return self._chain('<=', operand)

  def __gt__(self, operand):
    self._assert_sortable('>', operand)
    return self._chain('>', operand)

  def __ge__(self, operand):
    self._assert_sortable('>=', operand)
    return self._chain('>=', operand)

  def __eq__(self, operand):
    self._limit = 1
    return self._chain('==', operand)

  def __ne__(self, operand):
    self._limit = 1
    return self._chain('!=', operand)

  def one_of(self, *operands):
    self._limit = 1
    return self._chain('in', list(operands))

  # TODO: implement this
  # def regex(self, regex_str, case_insensitive=False):
  #   self._limit = 1
  #   self._chain('re', (regex_str, case_insensitive))
  #   return self

  def __repr__(self):
    return '<Field(' + (', ').join([ ("'" + x + "'" if type(x) is str else repr(x)) for x in self._keys ]) + ')>'
