locals {
  application_port = 8080
  environment      = "dev"
  service_name     = "dev-box"
  instance_name    = "${local.service_name}-${var.dev_box_id}"

  domain_names = {
    for app in ["oa", "vapi", "workstation"] : app => "${local.environment}-${var.dev_box_id}-${app}.${var.subdomain}"
  }

  same_account = data.aws_caller_identity.current.account_id == data.aws_caller_identity.dns.account_id

  # we cannot use count and for_each in the same resource, so we need to create a separate map for the same account domain names
  same_account_domain_names = local.same_account ? {} : local.domain_names

  tags = {
    application_family  = var.application_family
    dev_box_id          = var.dev_box_id
    dev_box_owner_name  = var.owner_name
    dev_box_owner_email = var.owner_email_address
    environment         = local.environment
    service_name        = local.service_name
    terraformed         = true
  }
}

data "aws_caller_identity" "current" {}

data "aws_caller_identity" "dns" {
  provider = aws.dns
}

data "aws_vpc" "main" {
  tags = {
    Name = var.vpc_name
  }
}

data "aws_acm_certificate" "certificate" {
  domain   = "*.${var.subdomain}"
  statuses = ["ISSUED"]
}

data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.main.id]
  }

  filter {
    name   = "tag:Name"
    values = var.subnet_names
  }
}

data "aws_ec2_managed_prefix_list" "vpn_ny" {
  name = "vpn-ny-users"
}

data "aws_ec2_managed_prefix_list" "orchard_prod_private" {
  name = "prod-orcd-private-subnet-prefix-list"
}

data "aws_s3_bucket" "logging_bucket_lb" {
  bucket = var.lb_logs_bucket_name
}

data "aws_ami" "debian" {
  most_recent = true

  owners = ["086679231553"]

  filter {
    name   = "name"
    values = ["debian-12-amd64-*"]
  }

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }
}

data "aws_wafv2_web_acl" "waf" {
  name  = var.waf_name
  scope = "REGIONAL"
}

data "aws_kms_alias" "ebs_key" {
  name = "alias/aws/ebs"
}

module "chef_bootstrap" {
  source = "git@github.com:theorchard/terraform-chef-bootstrap.git?ref=3.3.0"

  chef_role         = "dev_box"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.name
  aws_instance_name = local.instance_name

  node_attributes = {
    docker_webapps = {
      email_to_address = var.owner_email_address
      email_to_name    = var.owner_name
      oa_domain_name   = local.domain_names["oa"]
      vapi_domain_name = local.domain_names["vapi"]
      ws_domain_name   = local.domain_names["workstation"]
    }
  }
}

resource "aws_security_group" "load_balancer_security_group" {
  name        = "${local.instance_name}-lb-security-group"
  description = "Load balancer security group for ${local.instance_name}"
  vpc_id      = data.aws_vpc.main.id

  tags = local.tags
}

resource "aws_security_group_rule" "allow_https" {
  type      = "ingress"
  from_port = 443
  to_port   = 443
  protocol  = "TCP"
  prefix_list_ids = [
    data.aws_ec2_managed_prefix_list.vpn_ny.id,
    data.aws_ec2_managed_prefix_list.orchard_prod_private.id,
  ]
  security_group_id = aws_security_group.load_balancer_security_group.id
}

resource "aws_security_group_rule" "allow_egress_to_instance" {
  type                     = "egress"
  from_port                = local.application_port
  to_port                  = local.application_port
  protocol                 = "TCP"
  source_security_group_id = aws_security_group.instance_security_group.id
  security_group_id        = aws_security_group.load_balancer_security_group.id
}

resource "aws_lb_target_group" "target_group" {
  name                 = local.instance_name
  port                 = local.application_port
  protocol             = "HTTP"
  target_type          = "instance"
  deregistration_delay = "60"
  vpc_id               = data.aws_vpc.main.id

  health_check {
    enabled             = true
    healthy_threshold   = 3
    interval            = 10
    matcher             = "200"
    path                = "/hello/"
    port                = "traffic-port"
    protocol            = "HTTP"
    timeout             = 5
    unhealthy_threshold = 5
  }

  tags = local.tags
}

resource "aws_lb" "application_load_balancer" {
  name                       = local.instance_name
  internal                   = true
  load_balancer_type         = "application"
  idle_timeout               = 60
  security_groups            = [aws_security_group.load_balancer_security_group.id]
  subnets                    = data.aws_subnets.private.ids
  enable_deletion_protection = false

  access_logs {
    bucket  = data.aws_s3_bucket.logging_bucket_lb.bucket
    prefix  = "${data.aws_caller_identity.current.account_id}/${local.instance_name}"
    enabled = true
  }

  tags = local.tags
}

resource "aws_wafv2_web_acl_association" "load_balancer_waf_association" {
  resource_arn = aws_lb.application_load_balancer.arn
  web_acl_arn  = data.aws_wafv2_web_acl.waf.arn
}

resource "aws_lb_listener" "load_balancer_https_listener" {
  load_balancer_arn = aws_lb.application_load_balancer.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"
  certificate_arn   = data.aws_acm_certificate.certificate.arn

  default_action {
    target_group_arn = aws_lb_target_group.target_group.arn
    type             = "forward"
  }
}

resource "aws_security_group" "instance_security_group" {
  name        = "${local.instance_name}-instance-security-group"
  description = "Instance security group for ${local.instance_name}"
  vpc_id      = data.aws_vpc.main.id

  tags = merge(local.tags, {
    eiso-exception = "aws.08.30"
  })
}

resource "aws_security_group_rule" "allow_ssh_vpn" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "TCP"
  prefix_list_ids   = [data.aws_ec2_managed_prefix_list.vpn_ny.id]
  security_group_id = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_listener_http" {
  type                     = "ingress"
  from_port                = local.application_port
  to_port                  = local.application_port
  protocol                 = "TCP"
  source_security_group_id = aws_security_group.load_balancer_security_group.id
  security_group_id        = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.instance_security_group.id
}

resource "aws_launch_template" "launch_template" {
  # checkov:skip=CKV_AWS_79:terraform-chef-bootstrap needs IMDSv1
  description            = local.instance_name
  ebs_optimized          = true
  image_id               = data.aws_ami.debian.id
  instance_type          = var.instance_type
  key_name               = var.aws_key_name
  name                   = local.instance_name
  user_data              = base64encode(module.chef_bootstrap.user_data_output)
  vpc_security_group_ids = [aws_security_group.instance_security_group.id]

  block_device_mappings {
    device_name = data.aws_ami.debian.root_device_name
    ebs {
      volume_size = var.disk_size
      encrypted   = true
      kms_key_id  = data.aws_kms_alias.ebs_key.arn
    }
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.iam_instance_profile.name
  }

  tags = local.tags
}

resource "aws_autoscaling_group" "autoscaling_group" {
  name                      = "${local.instance_name}-autoscaling-group"
  min_size                  = 1
  max_size                  = 1
  desired_capacity          = 1
  health_check_type         = "ELB"
  health_check_grace_period = 2700
  wait_for_capacity_timeout = "90m"
  min_elb_capacity          = 1
  wait_for_elb_capacity     = 1
  vpc_zone_identifier       = data.aws_subnets.private.ids
  target_group_arns         = [aws_lb_target_group.target_group.arn]
  force_delete              = true

  launch_template {
    id      = aws_launch_template.launch_template.id
    version = "$Latest"
  }

  suspended_processes = [
    "ReplaceUnhealthy",
  ]

  tag {
    key                 = "Name"
    value               = local.instance_name
    propagate_at_launch = true
  }

  dynamic "tag" {
    for_each = local.tags
    content {
      key                 = tag.key
      value               = tag.value
      propagate_at_launch = true
    }
  }

  dynamic "tag" {
    for_each = var.map_migrated_tag == null ? [] : [1]
    content {
      key                 = "map-migrated"
      value               = var.map_migrated_tag
      propagate_at_launch = true
    }
  }
}

# Configure ASG to scale
resource "aws_autoscaling_schedule" "scale_in" {
  autoscaling_group_name = aws_autoscaling_group.autoscaling_group.name
  scheduled_action_name  = "${local.instance_name}-scale-in-schedule"
  min_size               = 0
  max_size               = 0
  desired_capacity       = 0
  start_time             = timeadd(timestamp(), "720h")
  #
  lifecycle {
    ignore_changes = [start_time]
  }
}
