#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# Project:  GDAL/OGR Test Suite
# Purpose:  Earth Engine Data API driver test suite.
# Author:   Even Rouault, even dot rouault at spatialys.com
#
###############################################################################
# Copyright (c) 2017, Planet Labs
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################

import json

import gdaltest
import pytest

from osgeo import gdal, ogr

pytestmark = pytest.mark.require_driver("EEDA")


###############################################################################


@pytest.fixture(autouse=True, scope="module")
def startup_and_cleanup():
    with gdal.config_option("CPL_CURL_ENABLE_VSIMEM", "YES"):
        yield

    gdal.Unlink("/vsimem/ee/")
    gdal.Unlink(
        "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?pageSize=1"
    )
    gdal.Unlink(
        "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?pageToken=myToken"
    )
    gdal.Unlink(
        "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?filter=raw%5Ffilter"
    )


###############################################################################
# Nominal case


def test_eeda_2():

    gdal.FileFromMemBuffer(
        "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?pageSize=1",
        json.dumps(
            {
                "images": [
                    {
                        "properties": {
                            "string_field": "bar",
                            "int_field": 1,
                            "int64_field": 123456789012,
                            "double_field": 1.23,
                        }
                    }
                ]
            }
        ),
    )

    # To please the unregistering of the persistent connection
    gdal.FileFromMemBuffer("/vsimem/ee/", "")

    with gdal.config_option("EEDA_BEARER", "mybearer"):

        with gdal.config_option("EEDA_URL", "/vsimem/ee/"):
            ds = ogr.Open("EEDA:collection")

        lyr = ds.GetLayer(0)

        assert lyr.TestCapability(ogr.OLCStringsAsUTF8) == 1

        assert lyr.TestCapability("foo") == 0

        assert lyr.GetLayerDefn().GetFieldCount() == 8 + 7 + 4

        assert lyr.GetExtent() == (-180.0, 180.0, -90.0, 90.0)

        assert lyr.GetFeatureCount() == -1

        gdal.FileFromMemBuffer(
            "/vsimem/ee/projects/earthengine-public/assets/collection:listImages",
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-public/assets/collection/first_feature",
                            "id": "collection/first_feature",
                            "updateTime": "2017-01-04T12:34:56.789Z",
                            "startTime": "2017-01-02T12:34:56.789Z",
                            "endTime": "2017-01-03T12:34:56.789Z",
                            "sizeBytes": 1,
                            "geometry": {
                                "type": "Polygon",
                                "coordinates": [
                                    [
                                        [2, 49],
                                        [2.1, 49],
                                        [2.1, 49.1],
                                        [2, 49.1],
                                        [2, 49],
                                    ]
                                ],
                            },
                            "properties": {
                                "string_field": "bar",
                                "int_field": 1,
                                "int64_field": 123456789012,
                                "double_field": 1.23,
                                "another_prop": 3,
                            },
                            "bands": [
                                {
                                    "id": "B1",
                                    "dataType": {
                                        "precision": "INT",
                                        "range": {"max": 255},
                                    },
                                    "grid": {
                                        "crsCode": "EPSG:32610",
                                        "affineTransform": {
                                            "translateX": 499980,
                                            "translateY": 4200000,
                                            "scaleX": 60,
                                            "scaleY": -60,
                                        },
                                        "dimensions": {"width": 1830, "height": 1831},
                                    },
                                }
                            ],
                        },
                        {
                            "name": "projects/earthengine-public/assets/collection/second_feature"
                        },
                    ],
                    "nextPageToken": "myToken",
                }
            ),
        )

        f = lyr.GetNextFeature()
        if (
            f.GetField("name")
            != "projects/earthengine-public/assets/collection/first_feature"
            or f.GetField("id") != "collection/first_feature"
            or f.GetField("gdal_dataset")
            != "EEDAI:projects/earthengine-public/assets/collection/first_feature"
            or f.GetField("updateTime") != "2017/01/04 12:34:56.789+00"
            or f.GetField("startTime") != "2017/01/02 12:34:56.789+00"
            or f.GetField("endTime") != "2017/01/03 12:34:56.789+00"
            or f.GetField("sizeBytes") != 1
            or f.GetField("band_count") != 1
            or f.GetField("band_max_width") != 1830
            or f.GetField("band_max_height") != 1831
            or f.GetField("band_min_pixel_size") != 60
            or f.GetField("band_upper_left_x") != 499980
            or f.GetField("band_upper_left_y") != 4200000
            or f.GetField("band_crs") != "EPSG:32610"
            or f.GetField("string_field") != "bar"
            or f.GetField("int_field") != 1
            or f.GetField("int64_field") != 123456789012
            or f.GetField("double_field") != 1.23
            or f.GetField("other_properties") != '{ "another_prop": 3 }'
            or f.GetGeometryRef().ExportToWkt()
            != "MULTIPOLYGON (((2 49,2.1 49.0,2.1 49.1,2.0 49.1,2 49)))"
        ):
            f.DumpReadable()
            pytest.fail()

        f = lyr.GetNextFeature()
        if (
            f.GetField("name")
            != "projects/earthengine-public/assets/collection/second_feature"
        ):
            f.DumpReadable()
            pytest.fail()

        gdal.FileFromMemBuffer(
            "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?pageToken=myToken",
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-public/assets/collection/third_feature"
                        }
                    ]
                }
            ),
        )

        f = lyr.GetNextFeature()
        if (
            f.GetField("name")
            != "projects/earthengine-public/assets/collection/third_feature"
        ):
            f.DumpReadable()
            pytest.fail()

        f = lyr.GetNextFeature()
        assert f is None

        lyr.ResetReading()

        f = lyr.GetNextFeature()
        if (
            f.GetField("name")
            != "projects/earthengine-public/assets/collection/first_feature"
        ):
            f.DumpReadable()
            pytest.fail()

        lyr.SetAttributeFilter("EEDA:raw_filter")

        gdal.FileFromMemBuffer(
            "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?filter=raw%5Ffilter",
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-public/assets/collection/raw_filter"
                        }
                    ]
                }
            ),
        )

        f = lyr.GetNextFeature()
        assert (
            f.GetField("name")
            == "projects/earthengine-public/assets/collection/raw_filter"
        )

        lyr.SetAttributeFilter(None)
        lyr.SetAttributeFilter(
            "startTime >= '1980-01-01T00:00:00Z' AND "
            + "string_field = 'bar' AND "
            + "int_field > 0 AND "
            + "int_field < 2 AND "
            + "int64_field >= 0 AND "
            + "int64_field <= 9999999999999 AND "
            + "double_field != 3.5 AND "
            + "string_field IN ('bar', 'baz') AND "
            + "NOT( int_field IN (0) OR double_field IN (3.5) )"
        )

        tmpfile = "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?region=%7B%20%22type%22%3A%20%22Polygon%22%2C%20%22coordinates%22%3A%20%5B%20%5B%20%5B%20%2D180%2E0%2C%20%2D90%2E0%20%5D%2C%20%5B%20%2D180%2E0%2C%2090%2E0%20%5D%2C%20%5B%20180%2E0%2C%2090%2E0%20%5D%2C%20%5B%20180%2E0%2C%20%2D90%2E0%20%5D%2C%20%5B%20%2D180%2E0%2C%20%2D90%2E0%20%5D%20%5D%20%5D%20%7D&filter=%28%28%28string%5Ffield%20%3D%20%22bar%22%20AND%20%28int%5Ffield%20%3E%200%20AND%20int%5Ffield%20%3C%202%29%29%20AND%20%28%28int64%5Ffield%20%3E%3D%200%20AND%20int64%5Ffield%20%3C%3D%209999999999999%29%20AND%20%28double%5Ffield%20%21%3D%203%2E5%20AND%20string%5Ffield%20%3D%20%22bar%22%20OR%20string%5Ffield%20%3D%20%22baz%22%29%29%29%20AND%20%28NOT%20%28int%5Ffield%20%3D%200%20OR%20double%5Ffield%20%3D%203%2E5%29%29%29&startTime=1980%2D01%2D01T00%3A00%3A00Z"
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-public/assets/collection/filtered_feature",
                            "updateTime": "2017-01-03T12:34:56.789Z",
                            "startTime": "2017-01-02T12:34:56.789Z",
                            "sizeBytes": 1,
                            "geometry": {
                                "type": "Polygon",
                                "coordinates": [
                                    [
                                        [2, 49],
                                        [2.1, 49],
                                        [2.1, 49.1],
                                        [2, 49.1],
                                        [2, 49],
                                    ]
                                ],
                            },
                            "properties": {
                                "string_field": "bar",
                                "int_field": 1,
                                "int64_field": 123456789012,
                                "double_field": 1.23,
                                "another_prop": 3,
                            },
                        },
                        {
                            "name": "projects/earthengine-public/assets/collection/second_feature"
                        },
                    ]
                }
            ),
        ):

            lyr.SetSpatialFilterRect(-180, -90, 180, 90)

            f = lyr.GetNextFeature()

        assert (
            f.GetField("name")
            == "projects/earthengine-public/assets/collection/filtered_feature"
        )

        lyr.SetSpatialFilter(None)

        # Test time equality with second granularity
        lyr.SetAttributeFilter(
            "startTime >= '1980-01-01T00:00:00Z' AND endTime <= '1980-01-02T23:59:59Z'"
        )

        tmpfile = "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?startTime=1980%2D01%2D01T00%3A00%3A00Z&endTime=1980%2D01%2D02T23%3A59%3A59Z"
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-public/assets/collection/filtered_feature",
                            "startTime": "1980-01-01T00:00:00Z",
                            "endTime": "1980-01-02T23:59:59Z",
                        },
                        {
                            "name": "projects/earthengine-public/assets/collection/second_feature"
                        },
                    ]
                }
            ),
        ):

            f = lyr.GetNextFeature()

        assert (
            f.GetField("name")
            == "projects/earthengine-public/assets/collection/filtered_feature"
        )

        # Test time equality with day granularity
        lyr.SetAttributeFilter("startTime = '1980-01-01' AND endTime = '1980-01-02'")

        tmpfile = "/vsimem/ee/projects/earthengine-public/assets/collection:listImages?startTime=1980%2D01%2D01T00%3A00%3A00Z&endTime=1980%2D01%2D02T23%3A59%3A59Z"
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-public/assets/collection/filtered_feature",
                            "startTime": "1980-01-01T12:00:00Z",
                            "endTime": "1980-01-02T23:59:59Z",
                        },
                        {
                            "name": "projects/earthengine-public/assets/collection/second_feature"
                        },
                    ]
                }
            ),
        ):

            f = lyr.GetNextFeature()

        assert (
            f.GetField("name")
            == "projects/earthengine-public/assets/collection/filtered_feature"
        )

        ds = None


###############################################################################
# Nominal case where collection is in eedaconf.json


def test_eeda_3():

    with gdal.config_options({"EEDA_BEARER": "mybearer", "EEDA_URL": "/vsimem/ee/"}):
        ds = ogr.Open("EEDA:##example_collection/example_subcollection")

        lyr = ds.GetLayer(0)

        assert lyr.GetLayerDefn().GetFieldCount() == 8 + 7 + 4
        ds = None


###############################################################################
# Test that name and id variants are handled correctly.


def test_eeda_4():

    with gdaltest.config_options(
        {"EEDA_BEARER": "mybearer", "EEDA_URL": "/vsimem/ee/"}
    ):

        # User asset ID ("users/**").
        tmpfile = "/vsimem/ee/projects/earthengine-legacy/assets/users/foo:listImages?pageSize=1"
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {
                    "images": [
                        {"name": "projects/earthengine-legacy/assets/users/foo/bar"}
                    ]
                }
            ),
        ):
            assert ogr.Open("EEDA:users/foo").GetLayer(0)

        # Project asset ID ("projects/**").
        tmpfile = "/vsimem/ee/projects/earthengine-legacy/assets/projects/foo:listImages?pageSize=1"
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {
                    "images": [
                        {"name": "projects/earthengine-legacy/assets/projects/foo/bar"}
                    ]
                }
            ),
        ):
            ds = ogr.Open("EEDA:projects/foo")
            assert ds.GetLayer(0)
        ds = None

        # Multi-folder project asset ID ("projects/foo/bar/baz").
        tmpfile = "/vsimem/ee/projects/earthengine-legacy/assets/projects/foo/bar/baz:listImages?pageSize=1"
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {
                    "images": [
                        {
                            "name": "projects/earthengine-legacy/assets/projects/foo/bar/baz/qux"
                        }
                    ]
                }
            ),
        ):
            ds = ogr.Open("EEDA:projects/foo/bar/baz")
            assert ds.GetLayer(0)
        ds = None

        # Public-catalog asset ID (e.g. "LANDSAT").
        tmpfile = (
            "/vsimem/ee/projects/earthengine-public/assets/foo:listImages?pageSize=1"
        )
        with gdaltest.tempfile(
            tmpfile,
            json.dumps(
                {"images": [{"name": "projects/earthengine-public/assets/foo/bar"}]}
            ),
        ):
            ds = ogr.Open("EEDA:foo")
            assert ds.GetLayer(0)
        ds = None

        # Asset name ("projects/*/assets/**").
        tmpfile = "/vsimem/ee/projects/foo/assets/bar:listImages?pageSize=1"
        with gdaltest.tempfile(
            tmpfile, json.dumps({"images": [{"name": "projects/foo/assets/bar/baz"}]})
        ):
            ds = ogr.Open("EEDA:projects/foo/assets/bar")
            assert ds.GetLayer(0)
        ds = None
