# This file is part of the Open Data Cube, see https://opendatacube.org for more information
#
# Copyright (c) 2015-2020 ODC Contributors
# SPDX-License-Identifier: Apache-2.0
from datetime import datetime
from dateutil.tz import tzutc

from datacube.model import Range
from datacube.ui import parse_expressions


def test_parse_empty_str():
    q = parse_expressions('')
    assert q == {}


def test_id_search():
    q = parse_expressions("id = 26931d17-7a4e-4b55-98e7-d6777fb61df6")
    assert q['id'] == "26931d17-7a4e-4b55-98e7-d6777fb61df6"

    q = parse_expressions('id = "26931d17-7a4e-4b55-98e7-d6777fb61df6"')
    assert q['id'] == "26931d17-7a4e-4b55-98e7-d6777fb61df6"


def test_simple_string():
    q = parse_expressions("region_code = 56KKD", "i=10", "f=10.3")
    assert q['region_code'] == '56KKD'
    assert q['i'] == 10
    assert q['f'] == 10.3


def test_between_expression():
    q = parse_expressions('time in [2014, 2015]')
    assert 'time' in q
    r = q['time']
    assert isinstance(r, Range)
    assert isinstance(r.begin, datetime)
    assert isinstance(r.end, datetime)

    for k in ('lon', 'lat', 'x', 'y'):
        q = parse_expressions('{} in [10, 11.3]'.format(k))
        assert k in q
        r = q[k]
        assert isinstance(r, Range)
        assert isinstance(r.begin, (int, float))
        assert isinstance(r.end, (int, float))
        assert r == Range(10, 11.3)


def test_parse_simple_expression():
    assert parse_expressions('platform = 4') == {'platform': 4}
    assert parse_expressions('platform = "LANDSAT_8"') == {'platform': 'LANDSAT_8'}
    assert parse_expressions('platform = LANDSAT_8') == {'platform': 'LANDSAT_8'}
    assert parse_expressions('platform = "LAND SAT_8"') == {'platform': 'LAND SAT_8'}

    assert parse_expressions('lat in [4, 6]') == {'lat': Range(4, 6)}


def test_parse_uri_expression():
    assert parse_expressions('uri = file:///f/data/test.nc') == {'uri': 'file:///f/data/test.nc'}
    assert parse_expressions('uri = "file:///f/data/test.nc"') == {'uri': 'file:///f/data/test.nc'}
    assert parse_expressions('uri = "file:///f/data/test me.nc"') == {'uri': 'file:///f/data/test me.nc'}
    assert parse_expressions('uri = file:///C:/f/data/test.nc') == {'uri': 'file:///C:/f/data/test.nc'}
    assert parse_expressions('uri = "file:///C:/f/data/test.nc"') == {'uri': 'file:///C:/f/data/test.nc'}
    assert parse_expressions('uri = "file:///C:/f/data/test me.nc"') == {'uri': 'file:///C:/f/data/test me.nc'}


def test_parse_dates():
    assert parse_expressions('time in 2014-03-02') == {
        'time': Range(begin=datetime(2014, 3, 2, 0, 0, tzinfo=tzutc()),
                      end=datetime(2014, 3, 2, 23, 59, 59, 999999, tzinfo=tzutc()))
    }

    assert parse_expressions('time in 2014-3-2') == {
        'time': Range(begin=datetime(2014, 3, 2, 0, 0, tzinfo=tzutc()),
                      end=datetime(2014, 3, 2, 23, 59, 59, 999999, tzinfo=tzutc()))
    }

    # A missing day defaults to the first of the month.
    # They are probably better off using in-expessions in these cases (eg. "time in 2013-01"), but it's here
    # for backwards compatibility.
    march_2014 = {
        'time': Range(begin=datetime(2014, 3, 1, 0, 0, tzinfo=tzutc()),
                      end=datetime(2014, 3, 31, 23, 59, 59, 999999, tzinfo=tzutc()))
    }
    assert parse_expressions('time in 2014-03') == march_2014
    assert parse_expressions('time in 2014-3') == march_2014

    implied_feb_march_2014 = {
        'time': Range(begin=datetime(2014, 2, 1, 0, 0, tzinfo=tzutc()),
                      end=datetime(2014, 3, 31, 23, 59, 59, 999999, tzinfo=tzutc()))
    }
    assert parse_expressions('time in [2014-02, 2014-03]') == implied_feb_march_2014


def test_parse_date_ranges():
    eighth_march_2014 = {
        'time': Range(datetime(2014, 3, 8, tzinfo=tzutc()), datetime(2014, 3, 8, 23, 59, 59, 999999, tzinfo=tzutc()))
    }
    assert parse_expressions('time in 2014-03-08') == eighth_march_2014
    assert parse_expressions('time in 2014-03-8') == eighth_march_2014

    march_2014 = {
        'time': Range(datetime(2014, 3, 1, tzinfo=tzutc()), datetime(2014, 3, 31, 23, 59, 59, 999999, tzinfo=tzutc()))
    }
    assert parse_expressions('time in 2014-03') == march_2014
    assert parse_expressions('time in 2014-3') == march_2014
    # Leap year, 28 days
    feb_2014 = {
        'time': Range(datetime(2014, 2, 1, tzinfo=tzutc()), datetime(2014, 2, 28, 23, 59, 59, 999999, tzinfo=tzutc()))
    }
    assert parse_expressions('time in 2014-02') == feb_2014
    assert parse_expressions('time in 2014-2') == feb_2014

    # Entire year
    year_2014 = {
        'time': Range(datetime(2014, 1, 1, tzinfo=tzutc()), datetime(2014, 12, 31, 23, 59, 59, 999999, tzinfo=tzutc()))
    }
    assert parse_expressions('time in 2014') == year_2014


def test_parse_multiple_simple_expressions():
    # Multiple expressions in one command-line statement.
    # Mixed whitespace:
    between_exp = parse_expressions('platform=LS8 lat in [-4, 23.5] instrument="OTHER"')
    assert between_exp == {'platform': 'LS8', 'lat': Range(-4, 23.5), 'instrument': 'OTHER'}
    # Range(x,y) is "equal" to (x, y). Check explicitly that it's a range:
    assert between_exp['lat'].begin == -4
