from __future__ import annotations

from datetime import datetime, timezone

import boto3
from botocore.stub import Stubber

from awspipe.aws import AwsSessionContext
from awspipe.providers.aws_tables import (
    fetch_aws_account,
    fetch_aws_ec2_instance,
    fetch_aws_region,
    fetch_aws_s3_bucket,
    fetch_aws_security_group,
    fetch_aws_subnet,
    fetch_aws_vpc,
)


class ClientMapSession:
    def __init__(self, clients: dict[str, object]) -> None:
        self._clients = clients

    def client(self, service_name: str, region_name: str | None = None):
        return self._clients[service_name]


def make_context(clients: dict[str, object]) -> AwsSessionContext:
    return AwsSessionContext(
        session=ClientMapSession(clients),
        profile="dev",
        region="eu-west-1",
        account_id="123456789012",
        caller_identity={
            "Account": "123456789012",
            "Arn": "arn:aws:iam::123456789012:user/tester",
            "UserId": "AIDAINTEGRATION",
        },
    )


def test_fetch_aws_account_uses_caller_identity() -> None:
    rows = fetch_aws_account(make_context({}))

    assert rows[0]["account_id"] == "123456789012"
    assert rows[0]["user_id"] == "AIDAINTEGRATION"


def test_fetch_aws_region_with_stubber() -> None:
    session = boto3.session.Session(
        aws_access_key_id="test",
        aws_secret_access_key="test",
        region_name="eu-west-1",
    )
    ec2 = session.client("ec2")
    stubber = Stubber(ec2)
    stubber.add_response(
        "describe_regions",
        {
            "Regions": [
                {
                    "Endpoint": "ec2.eu-west-1.amazonaws.com",
                    "RegionName": "eu-west-1",
                    "OptInStatus": "opt-in-not-required",
                }
            ]
        },
        {"AllRegions": False},
    )
    with stubber:
        rows = fetch_aws_region(make_context({"ec2": ec2}))

    assert rows == [
        {
            "profile_name": "dev",
            "account_id": "123456789012",
            "region": "eu-west-1",
            "arn": None,
            "title": "eu-west-1",
            "opt_in_status": "opt-in-not-required",
            "endpoint": "ec2.eu-west-1.amazonaws.com",
        }
    ]


def test_fetch_aws_s3_bucket_with_stubber() -> None:
    session = boto3.session.Session(
        aws_access_key_id="test",
        aws_secret_access_key="test",
        region_name="eu-west-1",
    )
    s3 = session.client("s3")
    stubber = Stubber(s3)
    stubber.add_response(
        "list_buckets",
        {
            "Buckets": [
                {
                    "Name": "awspipe-test-bucket",
                    "CreationDate": datetime(2026, 3, 9, tzinfo=timezone.utc),
                }
            ],
            "Owner": {"DisplayName": "tester", "ID": "owner-id"},
        },
    )
    stubber.add_response(
        "get_bucket_location",
        {"LocationConstraint": "eu-west-1"},
        {"Bucket": "awspipe-test-bucket"},
    )
    with stubber:
        rows = fetch_aws_s3_bucket(make_context({"s3": s3}))

    assert rows[0]["name"] == "awspipe-test-bucket"
    assert rows[0]["region"] == "eu-west-1"


def test_fetch_aws_ec2_vpc_subnet_and_security_group_with_stubber() -> None:
    session = boto3.session.Session(
        aws_access_key_id="test",
        aws_secret_access_key="test",
        region_name="eu-west-1",
    )
    ec2 = session.client("ec2")
    stubber = Stubber(ec2)
    stubber.add_response(
        "describe_instances",
        {
            "Reservations": [
                {
                    "Instances": [
                        {
                            "InstanceId": "i-123",
                            "InstanceType": "t3.micro",
                            "State": {"Name": "running"},
                            "VpcId": "vpc-123",
                            "SubnetId": "subnet-123",
                            "PrivateIpAddress": "10.0.0.10",
                            "PublicIpAddress": "54.1.2.3",
                            "LaunchTime": datetime(2026, 3, 9, tzinfo=timezone.utc),
                            "Tags": [{"Key": "Name", "Value": "test-instance"}],
                        }
                    ]
                }
            ]
        },
        {},
    )
    stubber.add_response(
        "describe_vpcs",
        {
            "Vpcs": [
                {
                    "VpcId": "vpc-123",
                    "CidrBlock": "10.0.0.0/16",
                    "State": "available",
                    "IsDefault": False,
                    "Tags": [{"Key": "Name", "Value": "test-vpc"}],
                }
            ]
        },
        {},
    )
    stubber.add_response(
        "describe_subnets",
        {
            "Subnets": [
                {
                    "SubnetId": "subnet-123",
                    "VpcId": "vpc-123",
                    "CidrBlock": "10.0.1.0/24",
                    "AvailabilityZone": "eu-west-1a",
                    "AvailableIpAddressCount": 251,
                    "Tags": [{"Key": "Name", "Value": "test-subnet"}],
                }
            ]
        },
        {},
    )
    stubber.add_response(
        "describe_security_groups",
        {
            "SecurityGroups": [
                {
                    "GroupId": "sg-123",
                    "GroupName": "test-sg",
                    "VpcId": "vpc-123",
                    "Description": "test",
                    "OwnerId": "123456789012",
                }
            ]
        },
        {},
    )
    context = make_context({"ec2": ec2})

    with stubber:
        instance_rows = fetch_aws_ec2_instance(context)
        vpc_rows = fetch_aws_vpc(context)
        subnet_rows = fetch_aws_subnet(context)
        sg_rows = fetch_aws_security_group(context)

    assert instance_rows[0]["instance_id"] == "i-123"
    assert vpc_rows[0]["vpc_id"] == "vpc-123"
    assert subnet_rows[0]["subnet_id"] == "subnet-123"
    assert sg_rows[0]["group_id"] == "sg-123"
