# VPC part
module "main_vpc" {
  source = "../../../modules/vpc/vpc_v2"

  name_prefix       = local.name_prefix
  cidr_second_octet = var.vpc["cidr_second_octet"]

  flow_logs = {
    gsirt = {
      log_destination      = "${data.aws_s3_bucket.logs.arn}/vpcflow/"
      log_destination_type = "s3"
      traffic_type         = "REJECT"
    }
  }

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "main_public_subnets" {
  source             = "../../../modules/vpc/subnet"
  name_prefix        = local.name_prefix
  subnets            = var.public_subnets
  vpc_id             = module.main_vpc.vpc_id
  is_public          = true
  cidr_second_octet  = var.vpc["cidr_second_octet"]
  availability_zones = local.availability_zones
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "main_public_routing" {
  source      = "../../../modules/vpc/routes"
  is_public   = true
  name_prefix = local.name_prefix
  vpc_id      = module.main_vpc.vpc_id
  vpc_cidr    = module.main_vpc.vpc_cidr
  igw_id      = module.main_vpc.vpc_igw
  subnets     = module.main_public_subnets.subnet_ids
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "main_private_subnets" {
  source             = "../../../modules/vpc/subnet"
  name_prefix        = local.name_prefix
  subnets            = var.private_subnets
  vpc_id             = module.main_vpc.vpc_id
  is_public          = false
  cidr_second_octet  = var.vpc["cidr_second_octet"]
  availability_zones = local.availability_zones
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "gsirt_subnet" {
  source             = "../../../modules/vpc/subnet"
  name_prefix        = local.name_prefix
  subnets            = var.gsirt_subnets
  vpc_id             = module.main_vpc.vpc_id
  is_public          = false
  cidr_second_octet  = var.vpc["cidr_second_octet"]
  availability_zones = [local.gsirt_az]
  custom_identifier  = "-gsirt"
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "main_nat_gateways" {
  source      = "../../../modules/vpc/nat"
  name_prefix = local.name_prefix
  # Not using NAT gateway redundancy in dev
  public_subnet_ids = [module.main_public_subnets.subnet_ids[1]]
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

# In some environments it's better to create multiple nat gateways, one per availability zone.
module "main_private_routing" {
  source         = "../../../modules/vpc/routes"
  is_public      = false
  name_prefix    = local.name_prefix
  vpc_id         = module.main_vpc.vpc_id
  vpc_cidr       = module.main_vpc.vpc_cidr
  nat_gateway_id = module.main_nat_gateways.nats[0].id
  subnets        = concat(module.main_private_subnets.subnet_ids, module.gsirt_subnet.subnet_ids)
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

# VPC endpoints for dynamodb and s3
locals {
  all_routetables = [
    module.main_public_routing.route_table_id,
    module.main_private_routing.route_table_id
  ]
}
module "s3_endpoint" {
  source       = "../../../modules/vpc/endpoint_gateway"
  service      = "s3"
  vpc_id       = module.main_vpc.vpc_id
  route_tables = local.all_routetables
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "dynamodb_endpoint" {
  source       = "../../../modules/vpc/endpoint_gateway"
  service      = "dynamodb"
  vpc_id       = module.main_vpc.vpc_id
  route_tables = local.all_routetables
  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

# Kinesis endpoints
data "aws_vpc_endpoint_service" "kinesis_streams" {
  service = "kinesis-streams"
}

data "aws_iam_policy_document" "kinesis_endpoint" {
  statement {
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    actions   = ["kinesis:*"]
    effect    = "Allow"
    resources = ["arn:aws:kinesis:${var.aws_region_id}:${local.account_id}:stream/${local.name_prefix}*"]
  }
  statement {
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    actions   = ["kinesis:ListStreams"]
    effect    = "Allow"
    resources = ["*"]
  }
}

resource "aws_vpc_endpoint" "kinesis_endpoint" {
  vpc_endpoint_type   = "Interface"
  vpc_id              = module.main_vpc.vpc_id
  service_name        = data.aws_vpc_endpoint_service.kinesis_streams.service_name
  policy              = data.aws_iam_policy_document.kinesis_endpoint.json
  private_dns_enabled = true
  subnet_ids          = module.main_private_subnets.subnet_ids
  security_group_ids  = [module.main_sg_map.kinesis_endpoint_id]

  tags = merge(
    local.common_tags,
    {
      Name                     = "${local.name_prefix}-kinesis-endpoint",
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

data "aws_vpc_endpoint_service" "secretsmanager" {
  service = "secretsmanager"
}

resource "aws_vpc_endpoint" "secretsmanager_endpoint" {
  vpc_endpoint_type   = "Interface"
  vpc_id              = module.main_vpc.vpc_id
  service_name        = data.aws_vpc_endpoint_service.secretsmanager.service_name
  private_dns_enabled = true
  subnet_ids          = module.main_private_subnets.subnet_ids
  security_group_ids  = [module.main_sg_map.sm_endpoint_id]

  tags = merge(
    local.common_tags,
    {
      Name                     = "${local.name_prefix}-kinesis-endpoint",
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "gsirt_regional_endpoints" {
  source = "../../../modules/gsirt_regional_endpoints"
}

module "gsirt_endpoint" {
  source            = "../../../modules/vpc/endpoint_gateway"
  service           = module.gsirt_regional_endpoints.regional_endpoints_service_name[var.aws_region_id]
  vpc_endpoint_type = "Interface"
  subnet_ids        = module.gsirt_subnet.subnet_ids
  vpc_id            = module.main_vpc.vpc_id
  cidr_second_octet = var.vpc["cidr_second_octet"]

  common_tags = merge(
    local.common_tags,
    {
      Name                     = format("%v-gsirt-endpoint", local.name_prefix)
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

# Peering to proxy network
module "sme_proxy_peering" {
  source                          = "../../../modules/vpc/peering/accepter"
  vpc_accepter_cidr               = module.main_vpc.vpc_cidr
  peering_connection_id           = var.sme_proxy_peering_id
  connection_name                 = "${upper(var.platform.name)}_${upper(var.platform.prefix)}_TO_PROXY_CLOUDOPS"
  acc_to_req_dest_cidrs           = ["10.12.249.0/24"]
  allow_remote_vpc_dns_resolution = false

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Networking",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_NTW"
    }
  )
}

module "apollo_peering" {
  source                = "../../../modules/vpc/peering/one-to-one-internal"
  vpc_requester_cidr    = module.main_vpc.vpc_cidr
  vpc_accepter_cidr     = "10.10.0.0/16"
  connection_name       = "${upper(var.platform.name)}_${upper(var.platform.prefix)}_TO_APOLLO_DEV"
  req_to_acc_dest_cidrs = ["10.10.10.0/24", "10.10.11.0/24", "10.10.12.0/24", "10.10.13.0/24", "10.10.14.0/24", "10.10.15.0/24"]
  acc_to_req_dest_cidrs = module.main_private_subnets.subnet_cidrs
  common_tags = merge(
    local.common_tags,
    {
      service                  = "VPN",
      plat_env_project_service = "${local.aggregated_tag}_VPN"
    }
  )
}

# Temporary peering until the release
module "apollo_prod_peering" {
  source                = "../../../modules/vpc/peering/one-to-one-external"
  vpc_requester_cidr    = module.main_vpc.vpc_cidr
  vpc_accepter_cidr     = "10.13.0.0/16"
  connection_name       = "${upper(var.platform.name)}_${upper(var.platform.prefix)}_TO_APOLLO_PROD"
  req_to_acc_dest_cidrs = ["10.13.16.0/24", "10.13.17.0/24", "10.13.18.0/24", ]
  acc_to_req_dest_cidrs = module.main_private_subnets.subnet_cidrs
  accepter_account_id   = module.aws_accounts_list.accounts.gdb-delphi-prod

  providers = {
    aws.requester = aws
    aws.accepter  = aws.delphi-prod
  }

  common_tags = merge(
    local.common_tags,
    {
      service                  = "VPN",
      plat_env_project_service = "${local.aggregated_tag}_VPN"
    }
  )
}

module "delphi-dev_delphi-qa" {
  source             = "../../../modules/vpc/peering/one-to-one-internal"
  vpc_requester_cidr = module.main_vpc.vpc_cidr
  vpc_accepter_cidr  = "10.31.0.0/16"
  connection_name    = "${upper(var.platform.name)}_${upper(var.platform.prefix)}_TO_DELPHI_QA"
  req_to_acc_dest_cidrs = [
    "10.31.13.0/24",
    "10.31.14.0/24",
    "10.31.15.0/24",
  ]
  acc_to_req_dest_cidrs = module.main_private_subnets.subnet_cidrs
}

data "aws_ec2_transit_gateway" "transit_gateway" {
  filter {
    name   = "options.amazon-side-asn"
    values = ["64513"]
  }
}

data "aws_ec2_managed_prefix_list" "vpn_ny_users" {
  filter {
    name   = "prefix-list-name"
    values = ["vpn-ny-users"]
  }
}

resource "aws_ec2_transit_gateway_vpc_attachment" "transit_gateway_attachment" {
  vpc_id             = module.main_vpc.vpc_id
  transit_gateway_id = data.aws_ec2_transit_gateway.transit_gateway.id
  subnet_ids = concat(
    module.main_private_subnets.subnet_ids,
    module.gsirt_subnet.subnet_ids
  )
}

resource "aws_route" "ny" {
  for_each = toset([module.main_private_routing.route_table_id, module.main_public_routing.route_table_id])

  route_table_id             = each.value
  destination_prefix_list_id = data.aws_ec2_managed_prefix_list.vpn_ny_users.id
  transit_gateway_id         = data.aws_ec2_transit_gateway.transit_gateway.id
}

# GRPS routes:
resource "aws_route" "grps" {
  route_table_id         = module.main_private_routing.route_table_id
  destination_cidr_block = var.grps_cidr
  transit_gateway_id     = data.aws_ec2_transit_gateway.transit_gateway.id
}
