import boto3
import gzip
from moto import mock_s3
import pytest
import os

from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist
from tests.builders.file import build_gzip_csv


@pytest.fixture(scope='function')
def aws_credentials():
    """Mocked AWS Credentials for moto."""
    os.environ['AWS_ACCESS_KEY_ID'] = 'testing'
    os.environ['AWS_SECRET_ACCESS_KEY'] = 'testing'
    os.environ['AWS_SECURITY_TOKEN'] = 'testing'
    os.environ['AWS_SESSION_TOKEN'] = 'testing'
    os.environ['AWS_DEFAULT_REGION'] = 'us-east-1'


@pytest.fixture(scope='function')
def s3(aws_credentials):
    with mock_s3():
        yield boto3.resource('s3', region_name='us-east-1')


@mock_s3
def test_read_object_s3_returns_object_content(s3):
    bucket = s3.create_bucket(Bucket="test_bucket")
    s3_object = bucket.Object("test_object.csv.gz")
    gzipped_content = build_gzip_csv(
        header=["id", "message", "comment"],
        rows=[["123", "A message", "A comment"], [
            "321", "Another message", "Another comment"]],
    )
    s3_object.put(
        Body=gzipped_content
    )

    expected = "id,message,comment\n123,A message,A comment\n321,Another message,Another comment"

    csv_stream = read_object_s3(s3, "s3://test_bucket/test_object.csv.gz")

    with gzip.open(csv_stream, mode="rt") as f:
        actual = f.read()

    assert actual == expected


@mock_s3
def test_write_object_s3_writes_object_content(s3):
    s3.create_bucket(Bucket="test_bucket")

    json_string = b'{"fruit": "mango"}'
    write_object_s3(s3, "s3://test_bucket/test_object.json", json_string)

    s3_object_response = s3.Object("test_bucket", "test_object.json").get()
    assert s3_object_response["Body"].read() == json_string


@mock_s3
def test_write_object_s3_writes_object_content_with_metadata(s3):
    s3.create_bucket(Bucket="test_bucket")

    json_string = b'{"fruit": "mango"}'
    metadata = {
        "start_date": "start-date",
        "end_date": "end-date"
    }
    write_object_s3(s3, "s3://test_bucket/test_object.json", json_string, metadata)

    s3_object_response = s3.Object("test_bucket", "test_object.json").get()
    assert s3_object_response["Metadata"] == metadata


@mock_s3
def test_objects_exist_returns_true_when_all_objects_exist(s3):
    s3.create_bucket(Bucket="test_bucket")

    object_one = "object-one"
    object_two = "object-two"

    write_object_s3(s3, f"s3://test_bucket/{object_one}", 'object-one-content')
    write_object_s3(s3, f"s3://test_bucket/{object_two}", 'object-two-content')

    result = objects_exist(s3, "test_bucket", [object_one, object_two])

    assert result


@mock_s3
def test_objects_exist_returns_false_when_only_one_object_exists(s3):
    s3.create_bucket(Bucket="test_bucket")

    object_one = "object-one"
    object_two = "object-two"

    write_object_s3(s3, f"s3://test_bucket/{object_one}", 'object-one-content')

    result = objects_exist(s3, "test_bucket", [object_one, object_two])

    assert not result


@mock_s3
def test_objects_exist_returns_false_when_no_objects_exist(s3):
    s3.create_bucket(Bucket="test_bucket")

    object_one = "object-one"
    object_two = "object-two"

    result = objects_exist(s3, "test_bucket", [object_one, object_two])

    assert not result

[((11, 1, 11, 33), 'pytest.fixture', 'pytest.fixture', (), '', False, 'import pytest\n'), ((21, 1, 21, 33), 'pytest.fixture', 'pytest.fixture', (), '', False, 'import pytest\n'), ((31, 22, 35, 5), 'tests.builders.file.build_gzip_csv', 'build_gzip_csv', (), '', False, 'from tests.builders.file import build_gzip_csv\n'), ((42, 17, 42, 74), 'chalicelib.s3.read_object_s3', 'read_object_s3', ({(42, 32, 42, 34): 's3', (42, 36, 42, 73): '"""s3://test_bucket/test_object.csv.gz"""'}, {}), "(s3, 's3://test_bucket/test_object.csv.gz')", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((55, 4, 55, 73), 'chalicelib.s3.write_object_s3', 'write_object_s3', ({(55, 20, 55, 22): 's3', (55, 24, 55, 59): '"""s3://test_bucket/test_object.json"""', (55, 61, 55, 72): 'json_string'}, {}), "(s3, 's3://test_bucket/test_object.json', json_string)", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((70, 4, 70, 83), 'chalicelib.s3.write_object_s3', 'write_object_s3', ({(70, 20, 70, 22): 's3', (70, 24, 70, 59): '"""s3://test_bucket/test_object.json"""', (70, 61, 70, 72): 'json_string', (70, 74, 70, 82): 'metadata'}, {}), "(s3, 's3://test_bucket/test_object.json', json_string, metadata)", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((83, 4, 83, 79), 'chalicelib.s3.write_object_s3', 'write_object_s3', ({(83, 20, 83, 22): 's3', (83, 24, 83, 56): 'f"""s3://test_bucket/{object_one}"""', (83, 58, 83, 78): '"""object-one-content"""'}, {}), "(s3, f's3://test_bucket/{object_one}', 'object-one-content')", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((84, 4, 84, 79), 'chalicelib.s3.write_object_s3', 'write_object_s3', ({(84, 20, 84, 22): 's3', (84, 24, 84, 56): 'f"""s3://test_bucket/{object_two}"""', (84, 58, 84, 78): '"""object-two-content"""'}, {}), "(s3, f's3://test_bucket/{object_two}', 'object-two-content')", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((86, 13, 86, 71), 'chalicelib.s3.objects_exist', 'objects_exist', ({(86, 27, 86, 29): 's3', (86, 31, 86, 44): '"""test_bucket"""', (86, 46, 86, 70): '[object_one, object_two]'}, {}), "(s3, 'test_bucket', [object_one, object_two])", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((98, 4, 98, 79), 'chalicelib.s3.write_object_s3', 'write_object_s3', ({(98, 20, 98, 22): 's3', (98, 24, 98, 56): 'f"""s3://test_bucket/{object_one}"""', (98, 58, 98, 78): '"""object-one-content"""'}, {}), "(s3, f's3://test_bucket/{object_one}', 'object-one-content')", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((100, 13, 100, 71), 'chalicelib.s3.objects_exist', 'objects_exist', ({(100, 27, 100, 29): 's3', (100, 31, 100, 44): '"""test_bucket"""', (100, 46, 100, 70): '[object_one, object_two]'}, {}), "(s3, 'test_bucket', [object_one, object_two])", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((112, 13, 112, 71), 'chalicelib.s3.objects_exist', 'objects_exist', ({(112, 27, 112, 29): 's3', (112, 31, 112, 44): '"""test_bucket"""', (112, 46, 112, 70): '[object_one, object_two]'}, {}), "(s3, 'test_bucket', [object_one, object_two])", False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), ((23, 9, 23, 18), 'moto.mock_s3', 'mock_s3', ({}, {}), '()', False, 'from moto import mock_s3\n'), ((44, 9, 44, 41), 'gzip.open', 'gzip.open', (), '', False, 'import gzip\n'), ((24, 14, 24, 59), 'boto3.resource', 'boto3.resource', (), '', False, 'import boto3\n')]