# Tests requiring S3 credentials.
# Collected here to make them easier to skip/xfail.

import logging
import sys

import boto3
from packaging.version import parse
import pytest

import rasterio
from rasterio._drivers import (
    GDALEnv, del_gdal_config, get_gdal_config, set_gdal_config, driver_count)
from rasterio.env import defenv, delenv, getenv, setenv, Env
from rasterio.errors import EnvError
from rasterio.rio.main import main_group


# Custom markers.
mingdalversion = pytest.mark.skipif(
    parse(rasterio.__gdal_version__) < parse('2.1.0dev'),
    reason="S3 raster access requires GDAL 2.1")

credentials = pytest.mark.skipif(
    not(boto3.Session()._session.get_credentials()),
    reason="S3 raster access requires credentials")


logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)

L8TIF = "s3://landsat-pds/L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B1.TIF"
httpstif = "https://landsat-pds.s3.amazonaws.com/L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B1.TIF"


def test_gdal_config_accessers():
    """Low level GDAL config access."""
    assert get_gdal_config('foo') is None
    set_gdal_config('foo', 'bar')
    assert get_gdal_config('foo') == 'bar'
    del_gdal_config('foo')
    assert get_gdal_config('foo') is None


# The 'gdalenv' fixture ensures that gdal configuration is deleted
# at the end of the test, making tests as isolates as GDAL allows.

def test_env_accessors(gdalenv):
    """High level GDAL env access"""
    defenv()
    setenv(foo='1', bar='2')
    assert getenv() == rasterio.env._env.options == {'foo': '1', 'bar': '2'}
    assert get_gdal_config('foo') == '1'
    assert get_gdal_config('bar') == '2'
    delenv()
    assert getenv() == rasterio.env._env.options == {}
    assert get_gdal_config('foo') is None
    assert get_gdal_config('bar') is None
    rasterio.env._env = None
    with pytest.raises(EnvError):
        delenv()
    with pytest.raises(EnvError):
        setenv()
    with pytest.raises(EnvError):
        getenv()


def test_no_aws_gdal_config(gdalenv):
    """Trying to set AWS-specific GDAL config options fails."""
    with pytest.raises(EnvError):
        Env(AWS_ACCESS_KEY_ID='x')
    with pytest.raises(EnvError):
        Env(AWS_SECRET_ACCESS_KEY='y')


def test_env_options(gdalenv):
    """Test env options."""
    env = Env(foo='x')
    assert env.options == {'foo': 'x'}
    assert not env.previous_options
    assert getenv() == rasterio.env._env.options == {}
    with env:
        assert getenv() == rasterio.env._env.options == {'foo': 'x'}
    assert getenv() == rasterio.env._env.options == {}


def test_aws_session(gdalenv):
    """Create an Env with a boto3 session."""
    aws_session = boto3.Session(
        aws_access_key_id='id', aws_secret_access_key='key',
        aws_session_token='token', region_name='null-island-1')
    s = rasterio.env.Env(aws_session=aws_session)
    assert s._creds.access_key == 'id'
    assert s._creds.secret_key == 'key'
    assert s._creds.token == 'token'
    assert s.aws_session.region_name == 'null-island-1'


def test_aws_session_credentials(gdalenv):
    """Create an Env with a boto3 session."""
    aws_session = boto3.Session(
        aws_access_key_id='id', aws_secret_access_key='key',
        aws_session_token='token', region_name='null-island-1')
    s = rasterio.env.Env(aws_session=aws_session)
    assert getenv() == rasterio.env._env.options == {}
    s.get_aws_credentials()
    assert getenv() == rasterio.env._env.options == {
        'aws_access_key_id': 'id', 'aws_region': 'null-island-1',
        'aws_secret_access_key': 'key', 'aws_session_token': 'token'}


def test_with_aws_session_credentials(gdalenv):
    """Create an Env with a boto3 session."""
    with Env(aws_access_key_id='id', aws_secret_access_key='key',
             aws_session_token='token', region_name='null-island-1') as s:
        assert getenv() == rasterio.env._env.options == {}
        s.get_aws_credentials()
        assert getenv() == rasterio.env._env.options == {
            'aws_access_key_id': 'id', 'aws_region': 'null-island-1',
            'aws_secret_access_key': 'key', 'aws_session_token': 'token'}


def test_session_env_lazy(monkeypatch, gdalenv):
    """Create an Env with AWS env vars."""
    monkeypatch.setenv('AWS_ACCESS_KEY_ID', 'id')
    monkeypatch.setenv('AWS_SECRET_ACCESS_KEY', 'key')
    monkeypatch.setenv('AWS_SESSION_TOKEN', 'token')
    with Env() as s:
        s.get_aws_credentials()
        assert getenv() == rasterio.env._env.options == {
            'aws_access_key_id': 'id', 'aws_secret_access_key': 'key',
            'aws_session_token': 'token'}
    monkeypatch.undo()


def test_open_with_default_env(gdalenv):
    """Read from a dataset with a default env."""
    with rasterio.open('tests/data/RGB.byte.tif') as dataset:
        assert dataset.count == 3


def test_open_with_env(gdalenv):
    """Read from a dataset with an explicit env."""
    with Env():
        with rasterio.open('tests/data/RGB.byte.tif') as dataset:
            assert dataset.count == 3


@mingdalversion
@credentials
def test_s3_open_with_session(gdalenv):
    """Read from S3 demonstrating lazy credentials."""
    with Env():
        with rasterio.open(L8TIF) as dataset:
            assert dataset.count == 1


@mingdalversion
@credentials
def test_s3_open_with_default_session(gdalenv):
    """Read from S3 using default env."""
    with rasterio.open(L8TIF) as dataset:
        assert dataset.count == 1


@mingdalversion
def test_open_https_vsicurl(gdalenv):
    """Read from HTTPS URL"""
    with Env():
        with rasterio.open(httpstif) as dataset:
            assert dataset.count == 1


# CLI tests.

@mingdalversion
@credentials
def test_s3_rio_info(runner):
    """S3 is supported by rio-info"""
    result = runner.invoke(main_group, ['info', L8TIF])
    assert result.exit_code == 0
    assert '"crs": "EPSG:32645"' in result.output


@mingdalversion
@credentials
def test_https_rio_info(runner):
    """HTTPS is supported by rio-info"""
    result = runner.invoke(main_group, ['info', httpstif])
    assert result.exit_code == 0
    assert '"crs": "EPSG:32645"' in result.output
