data "aws_availability_zones" "available" {}

locals {
    available_azs = sort(data.aws_availability_zones.available.names)

    {%- if env_collection.existing_vpc_config and env_collection.existing_vpc_config.public_subnet_cidrs %}
    num_public_subnets = length([
        {%- for cidr in env_collection.existing_vpc_config.public_subnet_cidrs %}
        "{{ cidr }}"{% if not loop.last %}, {% endif %}
        {%- endfor %}
    ])
    {%- else %}
    num_public_subnets = min(length(local.available_azs), 4)
    {%- endif %}

    {%- if env_collection.existing_vpc_config and env_collection.existing_vpc_config.private_subnet_cidrs %}
    num_private_subnets = length([
        {%- for cidr in env_collection.existing_vpc_config.private_subnet_cidrs %}
        "{{ cidr }}"{% if not loop.last %}, {% endif %}
        {%- endfor %}
    ])
    {%- else %}
    num_private_subnets = min(length(local.available_azs), 4)
    {%- endif %}

    {%- if env_collection.existing_vpc_config and env_collection.existing_vpc_config.public_subnet_ids %}
    public_subnet_ids = [
        {%- for subnet_id in env_collection.existing_vpc_config.public_subnet_ids %}
        "{{ subnet_id }}"{% if not loop.last %}, {% endif %}
        {%- endfor %}
    ]
    {%- else %}
    public_subnet_ids = []
    {%- endif %}

    {%- if env_collection.existing_vpc_config and env_collection.existing_vpc_config.private_subnet_ids %}
    private_subnet_ids = [
        {%- for subnet_id in env_collection.existing_vpc_config.private_subnet_ids %}
        "{{ subnet_id }}"{% if not loop.last %}, {% endif %}
        {%- endfor %}
    ]
    {%- else %}
    private_subnet_ids = []
    {%- endif %}

    {%- if env_collection.existing_vpc_config and env_collection.existing_vpc_config.public_subnet_cidrs %}
    provided_public_cidrs = [
        {%- for cidr in env_collection.existing_vpc_config.public_subnet_cidrs %}
        "{{ cidr }}"{% if not loop.last %}, {% endif %}
        {%- endfor %}
    ]
    {%- else %}
    provided_public_cidrs = []
    {%- endif %}

    {%- if env_collection.existing_vpc_config and env_collection.existing_vpc_config.private_subnet_cidrs %}
    provided_private_cidrs = [
        {%- for cidr in env_collection.existing_vpc_config.private_subnet_cidrs %}
        "{{ cidr }}"{% if not loop.last %}, {% endif %}
        {%- endfor %}
    ]
    {%- else %}
    provided_private_cidrs = []
    {%- endif %}
}

{% if env_collection.existing_vpc_config %}
data "aws_vpc" "{{ env_collection.instance_name }}" {
    id = "{{ env_collection.existing_vpc_config.instance_name }}"
}

locals {
    vpc_cidr_block = data.aws_vpc.{{ env_collection.instance_name }}.cidr_block
    netmask = tonumber(split("/", local.vpc_cidr_block)[1])
    newbits = max(24 - local.netmask, 1)
}

{% else %}

locals {
    vpc_cidr_block = "10.0.0.0/16"
    newbits = 8
}

resource "aws_vpc" "{{ env_collection.instance_name }}" {
    cidr_block = local.vpc_cidr_block

    enable_dns_hostnames = true
    enable_dns_support = true
}
{% endif %}

resource "aws_subnet" "{{ env_collection.instance_name }}_public" {
    vpc_id = {{ env_collection.vpc_resource_address }}.id
    count = length(local.public_subnet_ids) > 0 ? 0 : local.num_public_subnets
    availability_zone = element(local.available_azs, count.index)
    map_public_ip_on_launch = true
    cidr_block = length(local.provided_public_cidrs) > 0 ? element(local.provided_public_cidrs, count.index) : cidrsubnet(local.vpc_cidr_block, local.newbits, count.index)
}

{% if not (env_collection.existing_vpc_config and env_collection.existing_vpc_config.public_subnet_ids) %}
{% if env_collection.existing_vpc_config %}
data "aws_internet_gateway" "{{ env_collection.instance_name }}" {
    filter {
        name = "attachment.vpc-id"
        values = ["{{ env_collection.existing_vpc_config.instance_name }}"]
    }
}
{% endif %}

resource "aws_internet_gateway" "{{ env_collection.instance_name }}" {
    {% if env_collection.existing_vpc_config %}
    count = can(data.aws_internet_gateway.{{ env_collection.instance_name }}.arn) ? 0 : 1
    {% else %}
    count = 1
    {% endif %}
    vpc_id = {{ env_collection.vpc_resource_address }}.id
}

resource "aws_route_table" "{{ env_collection.instance_name }}_public" {
    vpc_id = {{ env_collection.vpc_resource_address }}.id

    route {
        cidr_block = "0.0.0.0/0"
        {% if env_collection.existing_vpc_config %}
        gateway_id = can(data.aws_internet_gateway.{{ env_collection.instance_name }}.arn) ? "${data.aws_internet_gateway.{{ env_collection.instance_name }}.id}" : "${aws_internet_gateway.{{ env_collection.instance_name }}[0].id}"
        {% else %}
        gateway_id = "${aws_internet_gateway.{{ env_collection.instance_name }}[0].id}"
        {% endif %}
    }
}

resource "aws_route_table_association" "{{ env_collection.instance_name }}_public" {
    count = local.num_public_subnets
    subnet_id = "${element(aws_subnet.{{ env_collection.instance_name }}_public.*.id, count.index)}"
    route_table_id = "${aws_route_table.{{ env_collection.instance_name }}_public.id}"
}
{% endif %}

resource "aws_subnet" "{{ env_collection.instance_name }}_private" {
    vpc_id = {{ env_collection.vpc_resource_address }}.id
    count = length(local.private_subnet_ids) > 0 ? 0 : local.num_private_subnets
    availability_zone = element(local.available_azs, count.index)
    map_public_ip_on_launch = false
    cidr_block = length(local.provided_private_cidrs) > 0 ? element(local.provided_private_cidrs, count.index) : cidrsubnet(local.vpc_cidr_block, local.newbits, count.index + local.num_public_subnets)
}

{% if not (env_collection.existing_vpc_config and env_collection.existing_vpc_config.private_subnet_ids) %}
resource "aws_route_table" "{{ env_collection.instance_name }}_private" {
    vpc_id = {{ env_collection.vpc_resource_address }}.id
    route {
        cidr_block = "0.0.0.0/0"
        {%-
            if not env_collection.existing_vpc_config or
            env_collection.get_terraform_output("aws_eip_id_" + env_collection.instance_name)
        %}
        nat_gateway_id = "${aws_nat_gateway.{{ env_collection.instance_name }}[0].id}"
        {%- else %}
        {# only create the eip if there are no existing nat gateways, otherwise the output above will exist #}
        nat_gateway_id = can(data.aws_nat_gateways.{{ env_collection.instance_name }}_gateways.ids) ? data.aws_nat_gateways.{{ env_collection.instance_name }}_gateways.ids[0] : "${aws_nat_gateway.{{ env_collection.instance_name }}[0].id}"
        {%- endif %}
    }
}

data "aws_nat_gateways" "{{ env_collection.instance_name }}_gateways" {
    vpc_id = {{ env_collection.vpc_resource_address }}.id
}

resource "aws_eip" "{{ env_collection.instance_name }}" {
    {# create the eip if we are already managing it #}
    {%-
        if not env_collection.existing_vpc_config or
        env_collection.get_terraform_output("aws_eip_id_" + env_collection.instance_name)
    %}
    count = 1
    {%- else %}
    {# only create the eip if there are no existing nat gateways, otherwise the output above will exist #}
    count = can(data.aws_nat_gateways.{{ env_collection.instance_name }}_gateways.ids) ? 0 : 1
    {%- endif %}
    domain = "vpc"
}

output "aws_eip_id_{{ env_collection.instance_name }}" {
    value = can(aws_eip.{{ env_collection.instance_name }}[0].id) ? aws_eip.{{ env_collection.instance_name }}[0].id : false
}

resource "aws_nat_gateway" "{{ env_collection.instance_name }}" {
    {# if the eip output exists it means we're managing the nat gateway #}
    {%-
        if not env_collection.existing_vpc_config or
        env_collection.get_terraform_output("aws_eip_id_" + env_collection.instance_name)
    %}
    count = 1
    {%- else %}
    {# otherwise, only create the nat gateway if there are none in the vpc #}
    count = can(data.aws_nat_gateways.{{ env_collection.instance_name }}_gateways.ids) ? 0 : 1
    {%- endif %}

    allocation_id = "${aws_eip.{{ env_collection.instance_name }}[0].id}"
    subnet_id = "${element(aws_subnet.{{ env_collection.instance_name }}_public.*.id, 0)}"
}

output "aws_nat_gateway_id_{{ env_collection.instance_name }}" {
    {%-
        if not env_collection.existing_vpc_config or
        env_collection.get_terraform_output("aws_eip_id_" + env_collection.instance_name)
    %}
    value = aws_nat_gateway.{{ env_collection.instance_name }}[0].id
    {%- else %}
    value = can(data.aws_nat_gateways.{{ env_collection.instance_name }}_gateways.ids) ? 0 : 1
    {%- endif %}
}

resource "aws_route_table_association" "{{ env_collection.instance_name }}_private" {
    count = local.num_private_subnets
    subnet_id = "${element(aws_subnet.{{ env_collection.instance_name }}_private.*.id, count.index)}"
    route_table_id = "${aws_route_table.{{ env_collection.instance_name }}_private.id}"
}
{% endif %}
