import json
from typing import Generator, Tuple

import petname  # type: ignore[import]
import pytest
from mypy_boto3_dynamodb.service_resource import Table
from mypy_boto3_s3.service_resource import Bucket
from mypy_boto3_s3.type_defs import CreateBucketConfigurationTypeDef
from mypy_boto3_sqs.service_resource import Queue

from nhs_aws_helpers import (
    ddb_table,
    dynamodb,
    events_client,
    s3_resource,
    sqs_resource,
)


@pytest.fixture(scope="session")
def session_temp_s3_bucket() -> Generator[Bucket, None, None]:

    resource = s3_resource()

    bucket_name = f"temp-{petname.generate()}"
    bucket = resource.create_bucket(
        Bucket=bucket_name, CreateBucketConfiguration=CreateBucketConfigurationTypeDef(LocationConstraint="eu-west-2")
    )
    yield bucket

    bucket.objects.all().delete()
    bucket.delete()


@pytest.fixture(scope="function")
def temp_s3_bucket(session_temp_s3_bucket) -> Generator[Bucket, None, None]:  # pylint: disable=redefined-outer-name

    bucket = session_temp_s3_bucket

    bucket.objects.all().delete()

    yield bucket


@pytest.fixture(scope="function")
def temp_event_bus() -> Generator[Tuple[Queue, str], None, None]:

    events = events_client()
    sqs = sqs_resource()

    queue_name = f"temp-{petname.Generate(words=2, separator='-')}"
    queue = sqs.create_queue(QueueName=queue_name)

    bus_name = f"temp-{petname.generate()}"
    events.create_event_bus(Name=bus_name)

    rule_name = f"temp-{petname.generate()}"
    events.put_rule(Name=rule_name, EventPattern=json.dumps({"account": ["000000000000"]}), EventBusName=bus_name)

    queue_arn = f"arn:aws:sqs:eu-west-2:000000000000:{queue_name}"
    target_id = f"temp-{petname.generate()}"
    events.put_targets(
        Targets=[dict(Id=target_id, Arn=queue_arn)],
        EventBusName=bus_name,
        Rule=rule_name,
    )

    yield queue, bus_name

    events.remove_targets(Rule=rule_name, EventBusName=bus_name, Ids=[target_id], Force=True)

    events.delete_rule(Name=rule_name, EventBusName=bus_name, Force=True)
    queue.delete()
    events.delete_event_bus(Name=bus_name)


@pytest.fixture(scope="function")
def temp_queue() -> Generator[Queue, None, None]:
    sqs = sqs_resource()

    queue_name = f"local-{petname.Generate(words=2, separator='-')}"
    queue = sqs.create_queue(QueueName=queue_name, Attributes={"VisibilityTimeout": "2"})

    yield queue

    queue.delete()


@pytest.fixture(scope="function")
def temp_fifo_queue() -> Generator[Queue, None, None]:

    sqs = sqs_resource()

    queue_name = f"local-{petname.Generate(words=2, separator='-')}.fifo"
    queue = sqs.create_queue(QueueName=queue_name, Attributes=dict(FifoQueue="true", VisibilityTimeout="2"))

    yield queue

    queue.delete()


def clone_schema(table):
    key_schema = table.key_schema

    attributes = table.attribute_definitions

    indexes = table.global_secondary_indexes

    if indexes:
        for index in indexes:
            del index["IndexStatus"]
            del index["IndexSizeBytes"]
            del index["ItemCount"]
            del index["IndexArn"]

    clone = {
        "KeySchema": key_schema,
        "AttributeDefinitions": attributes,
        "ProvisionedThroughput": {"ReadCapacityUnits": 1000, "WriteCapacityUnits": 1000},
    }

    if indexes:

        for index in indexes:
            index["ProvisionedThroughput"]["ReadCapacityUnits"] = 1000
            index["ProvisionedThroughput"]["WriteCapacityUnits"] = 1000
        clone["GlobalSecondaryIndexes"] = indexes

    return clone


def temp_dynamodb_table(source_table_name: str) -> Generator[Table, None, None]:
    """
    Create a table that copies the schema of <source_table> but uses a random name, can be used throughout
    a test and is deleted at the end.
    """
    ddb = dynamodb()

    table_name = f"pytest-{petname.Generate(words=4, separator='_')}"

    source_table = ddb_table(source_table_name)

    cloned = clone_schema(source_table)

    table = ddb.create_table(TableName=table_name, **cloned)

    yield table

    table.delete()
