""" InfluxAlchemy Query Tests. """
import sys
from datetime import date, datetime, timedelta
try:
    from datetime import timezone
except ImportError:
    from pytz import timezone

import influxdb
import mock
from influxalchemy.client import InfluxAlchemy
from influxalchemy.measurement import Measurement


@mock.patch("influxdb.InfluxDBClient.query")
def test_repr(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    query = client.query(Measurement.new("fizz"))
    assert repr(query) == "SELECT * FROM fizz;"


@mock.patch("influxdb.InfluxDBClient.query")
def test_execute(mock_qry):
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    query = client.query(Measurement.new("fizz").buzz)
    query.execute()
    mock_qry.assert_called_with("SELECT buzz FROM fizz;")


@mock.patch("influxdb.InfluxDBClient.query")
def test_filter(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    meas = Measurement.new("fizz")
    query = client.query(meas).filter(meas.buzz == "goo")
    assert repr(query) == "SELECT * FROM fizz WHERE (buzz = 'goo');"


@mock.patch("influxdb.InfluxDBClient.query")
def test_filter_time_naive(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    meas = Measurement.new("fizz")
    d = datetime(2016, 10, 1)
    query = client.query(meas).filter(meas.time >= d)
    assert repr(query) == \
        "SELECT * FROM fizz WHERE (time >= '2016-10-01T00:00:00+00:00');"


@mock.patch("influxdb.InfluxDBClient.query")
def test_filter_time_date(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    meas = Measurement.new("fizz")
    d = date(2016, 10, 1)
    query = client.query(meas).filter(meas.time >= d)
    assert repr(query) == "SELECT * FROM fizz WHERE (time >= '2016-10-01');"


@mock.patch("influxdb.InfluxDBClient.query")
def test_filter_time_aware(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    meas = Measurement.new("fizz")
    if sys.version_info.major >= 3:
        tz_vietnam = timezone(timedelta(hours=7, minutes=7))
    else:
        tz_vietnam = timezone('Asia/Ho_Chi_Minh')
    d_low = datetime(2016, 9, 1, tzinfo=tz_vietnam)
    d_high = datetime(2016, 10, 2, 8)
    query = client.query(meas).filter(meas.time.between(d_low, d_high))
    assert repr(query) == \
        "SELECT * FROM fizz WHERE (time >= '2016-09-01T00:00:00+07:07' "\
        "AND time <= '2016-10-02T08:00:00+00:00');"


@mock.patch("influxdb.InfluxDBClient.query")
def test_group_by(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    query = client.query(Measurement.new("fizz")).group_by("buzz")
    assert str(query) == "SELECT * FROM fizz GROUP BY buzz;"


@mock.patch("influxdb.InfluxDBClient.query")
def test_filter_by(mock_qry):
    mock_qry.side_effect = influxdb.exceptions.InfluxDBClientError(None)
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    query = client.query(Measurement.new("fizz")).filter_by(buzz="goo")
    assert str(query) == "SELECT * FROM fizz WHERE (buzz = 'goo');"


def test_tags():
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    fizz = Measurement.new("fizz")
    query = client.query(fizz.buzz, fizz.bug)
    assert str(query) == "SELECT buzz, bug FROM fizz;"


@mock.patch("influxalchemy.InfluxAlchemy.tags")
@mock.patch("influxalchemy.InfluxAlchemy.fields")
def test_get_tags_fields(mock_fields, mock_tags):
    mock_tags.return_value = ["fizz", "buzz"]
    mock_fields.return_value = ["foo", "goo"]
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    fizz = Measurement.new("fuzz")
    query = client.query(fizz)
    assert str(query) == "SELECT fizz, buzz, foo, goo FROM fuzz;"


@mock.patch("influxalchemy.InfluxAlchemy.tags")
@mock.patch("influxalchemy.InfluxAlchemy.fields")
def test_get_empty_tags_fields(mock_fields, mock_tags):
    mock_tags.return_value = []
    mock_fields.return_value = []
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    fizz = Measurement.new("fuzz")
    query = client.query(fizz)
    assert str(query) == "SELECT * FROM fuzz;"


@mock.patch("influxdb.InfluxDBClient.query")
def test_limit_1(mock_limit):
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    fizz = Measurement.new("fuzz")
    query = client.query(fizz).limit(1)
    assert str(query) == "SELECT * FROM fuzz LIMIT 1;"


@mock.patch("influxdb.InfluxDBClient.query")
def test_limit_2(mock_limit):
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    fizz = Measurement.new("fuzz")
    query = client.query(fizz).filter_by(vendor='quandl', market='XCME')
    assert str(query) == \
        "SELECT * FROM fuzz WHERE (market = 'XCME') AND (vendor = 'quandl');"


@mock.patch("influxdb.InfluxDBClient.query")
def test_limit_3(mock_limit):
    db = influxdb.InfluxDBClient(database="example")
    client = InfluxAlchemy(db)
    fizz = Measurement.new("fuzz")
    query = client.query(fizz)\
                  .filter(fizz.foo == '123')\
                  .filter(fizz.boo == '555')\
                  .limit(2)
    assert str(query) == \
        "SELECT * FROM fuzz WHERE (foo = '123') AND (boo = '555') LIMIT 2;"
