#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# Project:  GDAL/OGR Test Suite
# Purpose:  'gdal raster info' testing
# Author:   Even Rouault <even dot rouault @ spatialys.com>
#
###############################################################################
# Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
#
# SPDX-License-Identifier: MIT
###############################################################################

import json

import pytest

from osgeo import gdal, osr


def get_info_alg():
    return gdal.GetGlobalAlgorithmRegistry()["raster"]["info"]


def test_gdalalg_raster_info_stdout_text_default_format():
    import gdaltest
    import test_cli_utilities

    gdal_path = test_cli_utilities.get_gdal_path()
    if gdal_path is None:
        pytest.skip("gdal binary missing")
    out, _ = gdaltest.runexternal_out_and_err(
        f"{gdal_path} raster info data/utmsmall.tif"
    )
    assert out.startswith("Driver: GTiff/GeoTIFF")


def test_gdalalg_raster_info_stdout_json():
    import gdaltest
    import test_cli_utilities

    gdal_path = test_cli_utilities.get_gdal_path()
    if gdal_path is None:
        pytest.skip("gdal binary missing")
    out, _ = gdaltest.runexternal_out_and_err(
        f"{gdal_path} raster info --format json data/utmsmall.tif"
    )
    j = json.loads(out)
    assert len(j["bands"]) == 1


def test_gdalalg_raster_info():
    info = get_info_alg()
    assert info.ParseRunAndFinalize(["--format=text", "data/utmsmall.tif"])
    output_string = info["output-string"]
    assert output_string.startswith("Driver: GTiff/GeoTIFF")


def test_gdalalg_raster_info_mm_checksum():
    info = get_info_alg()
    assert info.ParseRunAndFinalize(
        ["--format=text", "--mm", "--checksum", "data/utmsmall.tif"]
    )
    output_string = info["output-string"]
    assert "   Computed Min/Max=0.000,255.000" in output_string
    assert "Checksum=" in output_string


def test_gdalalg_raster_info_stats():
    info = get_info_alg()
    ds = gdal.Translate("", "../gcore/data/byte.tif", format="MEM")
    info["input"] = ds
    assert info.ParseRunAndFinalize(["--stats"])
    output_string = info["output-string"]
    j = json.loads(output_string)
    assert "stdDev" in j["bands"][0]


def test_gdalalg_raster_info_approx_stats():
    info = get_info_alg()
    ds = gdal.Translate("", "../gcore/data/byte.tif", format="MEM")
    info["input"] = ds
    assert info.ParseRunAndFinalize(["--approx-stats"])
    output_string = info["output-string"]
    j = json.loads(output_string)
    assert "stdDev" in j["bands"][0]


def test_gdalalg_raster_info_hist():
    info = get_info_alg()
    ds = gdal.Translate("", "../gcore/data/byte.tif", format="MEM")
    info["input"] = ds
    assert info.ParseRunAndFinalize(["--hist"])
    output_string = info["output-string"]
    j = json.loads(output_string)
    assert "histogram" in j["bands"][0]


def test_gdalalg_raster_info_no_options():
    info = get_info_alg()
    ds = gdal.Translate("", "../gcore/data/byte.tif", format="MEM")
    info["input"] = ds
    assert info.ParseRunAndFinalize(
        ["--no-gcp", "--no-md", "--no-ct", "--no-fl", "--no-nodata", "--no-mask"]
    )


def test_gdalalg_raster_info_list_mdd():
    info = get_info_alg()
    ds = gdal.Translate("", "../gcore/data/byte.tif", format="MEM")
    ds.SetMetadataItem("foo", "bar", "MY_DOMAIN")
    info["input"] = ds
    assert info.ParseRunAndFinalize(["--list-mdd"])
    output_string = info["output-string"]
    j = json.loads(output_string)
    assert "MY_DOMAIN" in j["metadata"]["metadataDomains"]


def test_gdalalg_raster_info_mdd_all():
    info = get_info_alg()
    ds = gdal.Translate("", "../gcore/data/byte.tif", format="MEM")
    ds.SetMetadataItem("foo", "bar", "MY_DOMAIN")
    info["input"] = ds
    assert info.ParseRunAndFinalize(["--mdd=all"])
    output_string = info["output-string"]
    j = json.loads(output_string)
    assert j["metadata"] == {
        "": {"AREA_OR_POINT": "Area"},
        "IMAGE_STRUCTURE": {"INTERLEAVE": "BAND"},
        "MY_DOMAIN": {"foo": "bar"},
        "DERIVED_SUBDATASETS": {
            "DERIVED_SUBDATASET_1_NAME": "DERIVED_SUBDATASET:LOGAMPLITUDE:",
            "DERIVED_SUBDATASET_1_DESC": "log10 of amplitude of input bands from ",
        },
    }


def test_gdalalg_raster_info_list_subdataset():
    info = get_info_alg()
    assert info.ParseRunAndFinalize(
        ["--input=../gcore/data/tiff_with_subifds.tif", "--subdataset=2"]
    )
    output_string = info["output-string"]
    j = json.loads(output_string)
    assert j["description"] == "GTIFF_DIR:2:../gcore/data/tiff_with_subifds.tif"


def test_gdalalg_raster_info_list_subdataset_error():
    info = get_info_alg()
    with pytest.raises(
        Exception,
        match="Invalid value for 'subdataset' argument. Should be between 1 and 2",
    ):
        info.ParseRunAndFinalize(
            ["--input=../gcore/data/tiff_with_subifds.tif", "--subdataset=3"]
        )


def test_gdalalg_raster_info_list_subdataset_error_cannot_open_subdataset():
    info = get_info_alg()
    ds = gdal.GetDriverByName("MEM").Create("", 1, 1)
    ds.SetMetadataItem("SUBDATASET_1_DESC", "desc", "SUBDATASETS")
    ds.SetMetadataItem("SUBDATASET_1_NAME", "i_do_not_exist", "SUBDATASETS")
    info["input"] = ds
    with pytest.raises(
        Exception,
        match="i_do_not_exist",
    ):
        info.ParseRunAndFinalize(["--subdataset=1"])


@pytest.mark.require_driver("GDALG")
def test_gdalalg_raster_info_read_gdalg_with_input_format():
    info = get_info_alg()
    info["input"] = "../gdrivers/data/gdalg/read_byte.gdalg.json"
    info["input-format"] = "GDALG"
    assert info.Run()


def test_gdalalg_raster_info_pipeline():

    with gdal.alg.raster.pipeline(
        input="../gdrivers/data/small_world.tif",
        pipeline="read ! info",
    ) as alg:
        j = alg.Output()
        assert len(j["bands"]) == 3


@pytest.mark.require_proj(8, 2)  # For IAU testing
def test_gdalalg_raster_info_crs():

    with pytest.raises(
        Exception, match="'crs-format' cannot be set when 'format' is set to 'json'"
    ):
        gdal.alg.raster.info(
            input="../gcore/data/byte.tif", output_format="json", crs_format="WKT2"
        )

    with gdal.alg.raster.info(
        input="../gcore/data/byte.tif", output_format="text"
    ) as alg:
        output_string = alg.Output()
        assert (
            """Coordinate Reference System:
  - name: NAD27 / UTM zone 11N
  - ID: EPSG:26711
  - type: Projected
  - projection type: UTM zone 11N, Transverse Mercator
  - units: metre
  - area of use: North America..., west -120.00, south 26.93, east -114.00, north 78.13\n"""
            in output_string
        )

    with gdal.alg.raster.info(input="data/utmsmall.tif", output_format="text") as alg:
        output_string = alg.Output()
        assert """Coordinate Reference System:
  - name: NAD27 / UTM zone 11N
  - ID: EPSG:26711
  - type: Projected
  - projection type: Transverse Mercator
  - units: metre""" in output_string
        assert "  - area of use" not in output_string

    with gdal.alg.raster.info(
        input="../gdrivers/data/small_world.tif", output_format="text"
    ) as alg:
        output_string = alg.Output()
        assert (
            """Coordinate Reference System:
  - name: WGS 84
  - ID: EPSG:4326
  - type: Geographic 2D
  - area of use: World, west -180.00, south -90.00, east 180.00, north 90.00"""
            in output_string
        )
        assert "  - projection type" not in output_string
        assert "  - units" not in output_string

    src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1)
    srs = osr.SpatialReference()
    srs.SetFromUserInput("EPSG:9518")
    src_ds.SetSpatialRef(srs)
    with gdal.alg.raster.info(input=src_ds, output_format="text") as alg:
        output_string = alg.Output()
        assert "name: WGS 84 + EGM2008 height\n" in output_string
        assert "ID: EPSG:9518\n" in output_string
        assert "type: Compound of Geographic\n" in output_string
        assert "projection type" not in output_string
        assert "units" not in output_string
        assert (
            "area of use: World, west -180.00, south -90.00, east 180.00, north 90.00\n"
            in output_string
        )

    src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1)
    srs = osr.SpatialReference()
    srs.ImportFromProj4("+proj=longlat +ellps=GRS80")
    src_ds.SetSpatialRef(srs)
    with gdal.alg.raster.info(input=src_ds, output_format="text") as alg:
        output_string = alg.Output()
        assert 'Coordinate Reference System WKT:\nGEOGCRS["unknown",' in output_string

    src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1)
    srs = osr.SpatialReference()
    srs.SetFromUserInput("IAU_2015:30100")
    src_ds.SetSpatialRef(srs)
    with gdal.alg.raster.info(input=src_ds, output_format="text") as alg:
        output_string = alg.Output()
        assert "name: Moon (2015) - Sphere / Ocentric\n" in output_string
        assert "ID: urn:ogc:def:crs:IAU:2015:30100\n" in output_string

    with gdal.alg.raster.info(
        input="data/utmsmall.tif", output_format="text", crs_format="WKT2"
    ) as alg:
        output_string = alg.Output()
        assert (
            'Coordinate Reference System WKT:\nPROJCRS["NAD27 / UTM zone 11N"'
            in output_string
        )

    with gdal.alg.raster.info(
        input="data/utmsmall.tif", output_format="text", crs_format="PROJJSON"
    ) as alg:
        output_string = alg.Output()
        assert 'Coordinate Reference System PROJJSON:\n{\n  "$schema":' in output_string

    src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1)
    srs.SetFromUserInput("EPSG:3857")
    src_ds.SetSpatialRef(srs)
    with gdal.alg.raster.info(input=src_ds, output_format="text") as alg:
        output_string = alg.Output()
        # Check we don't repeat twice the conversion and projection method name,
        # that only differ by a hyphen.
        assert (
            "projection type: Popular Visualisation Pseudo Mercator\n"
            in output_string.replace("-", " ")
        )
