import datetime

from django.utils.dateparse import parse_date
from django.utils.translation import ugettext as _

from corehq.apps.es.case_search import case_property_query
from eulxml.xpath.ast import serialize


class XPathFunctionException(Exception):
    pass


def date(node):
    assert node.name == 'date'
    if len(node.args) != 1:
        raise XPathFunctionException(_("The \"date\" function only accepts a single argument"))
    arg = node.args[0]

    if isinstance(arg, int):
        return (datetime.date(1970, 1, 1) + datetime.timedelta(days=arg)).strftime("%Y-%m-%d")

    if isinstance(arg, str):
        try:
            parsed_date = parse_date(arg)
        except ValueError:
            raise XPathFunctionException(_("{} is not a valid date").format(arg))

        if parsed_date is None:
            raise XPathFunctionException(
                _("The \"date\" function only accepts strings of the format \"YYYY-mm-dd\"")
            )

        return arg

    raise XPathFunctionException(
        "The \"date\" function only accepts integers or strings of the format \"YYYY-mm-dd\""
    )


def selected(node, fuzzy):
    if len(node.args) != 2:
        raise XPathFunctionException(_("The \"selected\" function accepts exactly two arguments."))
    property_name = serialize(node.args[0])
    search_values = node.args[1]
    search_mode = None
    if 1 < len(search_values.split(' ')):
        search_mode = 'OR'  # This will actually make the query the same as with selected_any
    return case_property_query(property_name, search_values, fuzzy=fuzzy, mode=search_mode)


def selected_any(node, fuzzy):
    if len(node.args) != 2:
        raise XPathFunctionException(_("The \"selected-any\" function accepts exactly two arguments."))
    property_name = serialize(node.args[0])
    search_values = node.args[1]
    return case_property_query(property_name, search_values, fuzzy=fuzzy, mode='OR')


def selected_all(node, fuzzy):
    if len(node.args) != 2:
        raise XPathFunctionException(_("The \"selected-all\" function accepts exactly two arguments."))
    property_name = serialize(node.args[0])
    search_values = node.args[1]
    return case_property_query(property_name, search_values, fuzzy=fuzzy, mode='AND')


XPATH_VALUE_FUNCTIONS = {
    'date': date,
}

XPATH_QUERY_FUNCTIONS = {
    'selected': selected,
    'selected-any': selected_any,
    'selected-all': selected_all,
}

@@ -1116,24 +1116,25 @@
 )%0A%0A%0Adef 
+_
 selected
 (node, f
@@ -1125,16 +1125,22 @@
 selected
+_query
 (node, f
@@ -1135,32 +1135,42 @@
 uery(node, fuzzy
+, operator
 ):%0A    if len(no
@@ -1227,25 +1227,25 @@
 n(_(
+f
 %22The 
-%5C%22selected%5C%22
+%7Bnode.name%7D
  fun
@@ -1365,167 +1365,8 @@
 %5B1%5D%0A
-    search_mode = None%0A    if 1 %3C len(search_values.split(' ')):%0A        search_mode = 'OR'  # This will actually make the query the same as with selected_any%0A
     
@@ -1444,19 +1444,16 @@
 ode=
-search_mode
+operator
 )%0A%0A%0A
@@ -1464,20 +1464,16 @@
 selected
-_any
 (node, f
@@ -1487,272 +1487,129 @@
     
-if len(node.args) != 2:%0A        raise XPathFunctionException(_(%22The %5C%22selected-any%5C%22 function accepts exactly two arguments.%22))%0A    property_name = serialize(node.args%5B0%5D)%0A    search_values = node.args%5B1%5D%0A    return case_property_query(property_name, search_values
+return _selected_query(node, fuzzy=fuzzy, operator='or')%0A%0A%0Adef selected_any(node, fuzzy):%0A    return _selected_query(node
 , fu
@@ -1623,16 +1623,20 @@
 zy, 
-mode='OR
+operator='or
 ')%0A%0A
@@ -1675,296 +1675,63 @@
     
-if len(node.args) != 2:%0A        raise XPathFunctionException(_(%22The %5C%22selected-all%5C%22 function accepts exactly two arguments.%22))%0A    property_name = serialize(node.args%5B0%5D)%0A    search_values = node.args%5B1%5D%0A    return case_property_query(property_name, search_values, fuzzy=fuzzy, mode='AND
+return _selected_query(node, fuzzy=fuzzy, operator='and
 ')%0A%0A

use common function for query functions