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, 'pytest.fixture', 'pytest.fixture', False, 'import pytest\n'), (21, 'pytest.fixture', 'pytest.fixture', False, 'import pytest\n'), (31, 'tests.builders.file.build_gzip_csv', 'build_gzip_csv', False, 'from tests.builders.file import build_gzip_csv\n'), (42, 'chalicelib.s3.read_object_s3', 'read_object_s3', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (55, 'chalicelib.s3.write_object_s3', 'write_object_s3', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (70, 'chalicelib.s3.write_object_s3', 'write_object_s3', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (83, 'chalicelib.s3.write_object_s3', 'write_object_s3', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (84, 'chalicelib.s3.write_object_s3', 'write_object_s3', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (86, 'chalicelib.s3.objects_exist', 'objects_exist', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (98, 'chalicelib.s3.write_object_s3', 'write_object_s3', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (100, 'chalicelib.s3.objects_exist', 'objects_exist', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (112, 'chalicelib.s3.objects_exist', 'objects_exist', False, 'from chalicelib.s3 import read_object_s3, write_object_s3, objects_exist\n'), (23, 'moto.mock_s3', 'mock_s3', False, 'from moto import mock_s3\n'), (44, 'gzip.open', 'gzip.open', False, 'import gzip\n'), (24, 'boto3.resource', 'boto3.resource', False, 'import boto3\n')]