module "default_tags" {
  source             = "git@github.com:theorchard/terraform-default-tags.git//?ref=2.0.0"
  environment        = var.environment
  application_family = var.application_family
  service_name       = var.service_name
  team_name          = var.team_name
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = module.default_tags.tags
  }
}

provider "aws" {
  region  = var.aws_region
  alias   = "prod"
  profile = "prod"

  default_tags {
    tags = module.default_tags.tags
  }
}

provider "aws" {
  region  = var.aws_region
  alias   = "networking"
  profile = "networking"

  default_tags {
    tags = module.default_tags.tags
  }
}

terraform {
  backend "s3" {
    bucket  = "prod-accounting-terraform-state"
    key     = "prod/statementdb/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_caller_identity" "current" {}

data "aws_iam_policy" "shared_ami_kms_policy" {
  name = "KMS-shared-base-amis-RO"
}

data "aws_route53_zone" "route53_zone_theorchard_io_networking" {
  provider = aws.networking

  name         = "theorchard.io."
  private_zone = false
}

data "aws_route53_zone" "route53_zone" {
  name         = "prod-accounting.theorchard.io."
  private_zone = false
}

data "cloudflare_zone" "cloudflare_domain" {
  filter = {
    name = "theorchard.com"
  }
}

# Get the latest PDE Debian 12 AMI id
data "aws_ami" "debian" {
  most_recent = true

  owners = ["086679231553"]

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

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

# We presently cannot use cross-account security groups to/from the orcd prod account, or else
# we would allow the following services:
# - Jenkins agents (pipeline)
# - Jenkins task agents (scheduler)
# - Snowflake ETL ECS tasks
# - Kafka Connect JDBC Sink NR ECS tasks
# - Kafka Connect Debezium SFD ECS tasks
# - Looker RDS Proxy ECS tasks (maybe)

# Instead, these are the CIDR blocks for the private subnets in the orcd prod account,
# where these services are running.
data "aws_ec2_managed_prefix_list" "orchard_prod_private_prefix_list" {
  name = "prod-orcd-private-subnet-prefix-list"
}

data "aws_ec2_managed_prefix_list" "vpn_sme_internal_primary_prefix_list" {
  name = "vpn-sme-internal-primary"
}

# # Slaughterhouse instance security group
data "aws_security_group" "slaughterhouse_instance_security_group" {
  name = "${var.environment}-slaughterhouse-instance-sg"
}

# ECS extract-files task security group
data "aws_security_group" "ecs_abacus_extract_sales_task_security_group" {
  name = "${var.environment}-ecs-abacus-extract-sales-task-security-group"
}

# # ECS task security group for prod-looker-rds-proxy
# data "aws_security_group" "looker_rds_proxy_security_group" {
#   name = "${var.environment}-looker-rds-proxy-task-security-group"
# }

module "vpc_info" {
  source = "git@github.com:theorchard/terraform-vpc-info.git//?ref=3.2.2"

  environment = var.environment
}

data "aws_subnet" "instance_subnet" {
  filter {
    name   = "vpc-id"
    values = [module.vpc_info.vpc_id]
  }
  filter {
    name = "tag:Name"
    values = [
      "${var.environment}_private_subnet_0",
    ]
  }
}

data "aws_iam_policy_document" "assume_instance_role" {
  statement {
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"
      identifiers = [
        "ec2.amazonaws.com",
      ]
    }
  }
}

# Create KMS key for EBS encryption
resource "aws_kms_key" "kms_key" {
  description             = "${var.environment}-${var.service_name}"
  enable_key_rotation     = true
  deletion_window_in_days = 30

  tags = {
    environment        = var.environment
    service_name       = var.service_name
    application_family = var.application_family
    map-migrated       = var.map_migrated_tag
    terraformed        = true
  }
}

resource "aws_kms_alias" "kms_alias" {
  name          = "alias/${var.environment}-${var.service_name}"
  target_key_id = aws_kms_key.kms_key.key_id
}

data "aws_iam_policy_document" "kms_usage_policy" {
  statement {
    actions = [
      "kms:CreateGrant",
      "kms:Decrypt",
      "kms:DescribeKey",
      "kms:Encrypt",
      "kms:GenerateDataKey*",
      "kms:ReEncrypt*",
      "kms:RetireGrant",
    ]

    resources = [
      aws_kms_key.kms_key.arn,
    ]
  }
}

# Instance role
resource "aws_iam_role" "instance_iam_role" {
  name               = "${var.environment}-${var.service_name}-instance-role"
  assume_role_policy = data.aws_iam_policy_document.assume_instance_role.json
}

resource "aws_iam_instance_profile" "iam_instance_profile" {
  name = "${var.environment}-${var.service_name}-instance-profile"
  role = aws_iam_role.instance_iam_role.name
}

# Write access to royalties sales files bucket
module "s3_read_write_policy" {
  source = "git@github.com:theorchard/terraform-iam-policy-templates.git//documents/s3/buckets_with_prefixes?ref=0.4.0"

  buckets = [
    { bucket = "${var.environment}-royalties-sales-files" },
  ]
  action_types = ["read", "write"]
}

resource "aws_iam_policy" "s3_royalties_sales_file_rw_policy" {
  name   = "S3-${var.environment}-royalties-sales-files-RW"
  policy = module.s3_read_write_policy.policy.json
}

# Create KMS policy
resource "aws_iam_policy" "kms_policy" {
  name   = "KMS-${var.environment}-${var.service_name}-key-usage-policy"
  policy = data.aws_iam_policy_document.kms_usage_policy.json
}

# Attach KMS policy to role
resource "aws_iam_role_policy_attachment" "kms_policy_attachment" {
  role       = aws_iam_role.instance_iam_role.name
  policy_arn = aws_iam_policy.kms_policy.arn
}

resource "aws_iam_role_policy_attachment" "shared_ami_kms_policy_attachment" {
  role       = aws_iam_role.instance_iam_role.name
  policy_arn = data.aws_iam_policy.shared_ami_kms_policy.arn
}

resource "aws_iam_role_policy_attachment" "s3_royalties_sales_file_rw_policy_attachment" {
  role       = aws_iam_role.instance_iam_role.name
  policy_arn = aws_iam_policy.s3_royalties_sales_file_rw_policy.arn
}

# Uploading royalties sales files now required assuming a cross-account role
data "aws_iam_policy_document" "assume_s3_upload_role_policy_document" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRole"]
    resources = [
      "arn:aws:iam::437795906767:role/${var.environment}-${var.service_name}-upload-role"
    ]
  }
}

resource "aws_iam_policy" "assume_s3_upload_role_policy" {
  name   = "STS-${var.environment}-${var.service_name}-AssumeRole-policy"
  policy = data.aws_iam_policy_document.assume_s3_upload_role_policy_document.json
}

resource "aws_iam_role_policy_attachment" "assume_s3_upload_role_policy_attachment" {
  role       = aws_iam_role.instance_iam_role.name
  policy_arn = aws_iam_policy.assume_s3_upload_role_policy.arn
}

# Security group for instance
resource "aws_security_group" "instance_security_group" {
  name        = "${var.environment}-${var.service_name}-instance-security-group"
  description = "Instance security group for ${var.environment}-${var.service_name}"
  vpc_id      = module.vpc_info.vpc_id

  tags = {
    environment        = var.environment
    application_family = var.application_family
    service_name       = var.service_name
    map-migrated       = var.map_migrated_tag
    eiso-exception     = "aws.08.30"
    terraformed        = true
  }
}

resource "aws_security_group_rule" "allow_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "TCP"
  cidr_blocks       = var.ssh_ingress_cidr_blocks
  security_group_id = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_mysql" {
  type              = "ingress"
  from_port         = 3306
  to_port           = 3306
  protocol          = "TCP"
  cidr_blocks       = var.mysql_ingress_cidr_blocks
  security_group_id = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_mysql_from_services" {
  for_each                 = toset(local.downstream_services_security_groups)
  type                     = "ingress"
  from_port                = 3306
  to_port                  = 3306
  protocol                 = "TCP"
  source_security_group_id = each.value
  security_group_id        = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_mysql_orchard_prod_private_prefix_list" {
  type              = "ingress"
  from_port         = 3306
  to_port           = 3306
  protocol          = "TCP"
  prefix_list_ids   = [data.aws_ec2_managed_prefix_list.orchard_prod_private_prefix_list.id]
  security_group_id = aws_security_group.instance_security_group.id
}

# # Slaughterhouse access to statementdb
resource "aws_security_group_rule" "prod_slaughterhouse" {
  type                     = "ingress"
  from_port                = 3306
  to_port                  = 3306
  protocol                 = "TCP"
  source_security_group_id = data.aws_security_group.slaughterhouse_instance_security_group.id
  security_group_id        = aws_security_group.instance_security_group.id
}

# ECS extract-files task access to statementdb
resource "aws_security_group_rule" "qa_ecs_abacus_extract_sales_task" {
  type                     = "ingress"
  from_port                = 22
  to_port                  = 22
  protocol                 = "TCP"
  source_security_group_id = data.aws_security_group.ecs_abacus_extract_sales_task_security_group.id
  security_group_id        = aws_security_group.instance_security_group.id
}

# # ECS task security group for prod-looker-rds-proxy
# resource "aws_security_group_rule" "prod_looker_rds_proxy" {
#   type                     = "ingress"
#   from_port                = 3306
#   to_port                  = 3306
#   protocol                 = "TCP"
#   source_security_group_id = data.aws_security_group.looker_rds_proxy_security_group.id
#   security_group_id        = aws_security_group.instance_security_group.id
# }

resource "aws_security_group_rule" "allow_mysql_vpn_sme_internal_primary_prefix_list" {
  type              = "ingress"
  from_port         = 3306
  to_port           = 3306
  protocol          = "TCP"
  prefix_list_ids   = [data.aws_ec2_managed_prefix_list.vpn_sme_internal_primary_prefix_list.id]
  security_group_id = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_instance_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
}

# Using the EBS resource allows
# in-place changes to be detected by Terraform
resource "aws_ebs_volume" "volume" {
  availability_zone = data.aws_subnet.instance_subnet.availability_zone
  encrypted         = true
  type              = "io2"
  size              = 32000
  iops              = 8000
  kms_key_id        = aws_kms_key.kms_key.arn
  final_snapshot    = true

  tags = {
    Name               = "${var.environment}-mysql-${var.service_name}"
    environment        = var.environment
    application_family = var.application_family
    service_name       = var.service_name
    map-migrated       = var.map_migrated_tag
    terraformed        = true
  }
}

resource "aws_volume_attachment" "attachment" {
  device_name = "/dev/sdb"
  volume_id   = aws_ebs_volume.volume.id
  instance_id = aws_instance.mysql.id
}

resource "aws_instance" "mysql" {
  # checkov:skip=CKV_AWS_79:Debian AMI need metadata endpoint v1 enabled or SSH does not work.
  ami                                  = data.aws_ami.debian.id
  key_name                             = "${var.environment}-mysql-${var.service_name}01"
  monitoring                           = true
  subnet_id                            = data.aws_subnet.instance_subnet.id
  vpc_security_group_ids               = [aws_security_group.instance_security_group.id]
  associate_public_ip_address          = false
  iam_instance_profile                 = aws_iam_instance_profile.iam_instance_profile.name
  instance_type                        = "r5.8xlarge"
  ebs_optimized                        = true
  instance_initiated_shutdown_behavior = "stop"
  disable_api_termination              = true
  user_data                            = module.statementdb_bootstrap.user_data_output

  root_block_device {
    volume_type           = "gp3"
    volume_size           = 100
    delete_on_termination = false
    encrypted             = true
    kms_key_id            = aws_kms_key.kms_key.arn
  }

  volume_tags = merge(module.default_tags.tags, {
    Name         = "${var.environment}-mysql-${var.service_name}",
    map-migrated = var.map_migrated_tag
  })

  tags = merge(module.default_tags.tags, {
    Name         = "${var.environment}-mysql-${var.service_name}",
    map-migrated = var.map_migrated_tag
  })

  lifecycle {
    ignore_changes = [
      ami,
    ]
  }
}

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

  chef_role         = "${var.environment}_mysql_statementdb"
  aws_instance_name = "${var.environment}-${var.service_name}"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.id

  node_attributes = {
    datadog = {
      tags = {
        environment  = var.environment
        service_name = var.service_name
      }
    }
  }
}


# TODO: get IDs and uncomment this
# module "datadog_mysql" {
#   source                                    = "git@github.com:theorchard/terraform-datadog.git//modules/mysql?ref=6.18.2"
#   environment                               = var.environment
#   host_name                                 = "${var.environment}-mysql-${var.service_name}01"
#   mysql_disk_space_monitor_enabled          = true
#   mysql_availability_monitor_enabled        = true
#   mysql_connection_monitor_enabled          = true
#   mysql_cpu_monitor_enabled                 = true
#   mysql_memory_monitor_enabled              = true
#   mysql_slow_queries_monitor_enabled        = true
#   ebs_widgets_enabled                       = true
#   warning_number_disk_utilization           = 80
#   warning_recovery_number_disk_utilization  = 75
#   critical_number_disk_utilization          = 90
#   critical_recovery_number_disk_utilization = 85
#   mysql_data_volume_ebs_volume_id           = "vol-TODO"
#   mysql_data_volume_device_name             = "/dev/nvme1n1"
#   mysql_system_disk_device_name             = "/dev/nvme0n1p1"
#   notification_endpoints                    = "@slack-devops @bgarcia@theorchard.com @jkass@theorchard.com"
#   escalation_notification_endpoints         = "@slack-devops @bgarcia@theorchard.com @jkass@theorchard.com"
# }

resource "aws_route53_record" "statementdb_accounting_zone_dns_record" {
  zone_id = data.aws_route53_zone.route53_zone.zone_id
  name    = "${var.environment}-${var.service_name}"
  type    = "A"
  ttl     = "60"
  records = [aws_instance.mysql.private_ip]
}

resource "cloudflare_dns_record" "statementdb_a_record" {
  zone_id = data.cloudflare_zone.cloudflare_domain.zone_id
  name    = "statementdb"
  type    = "A"
  ttl     = 60
  content = aws_instance.mysql.private_ip
}

resource "aws_route53_record" "statementdb_theorchard_io_zone_networking_dns_record" {
  provider = aws.networking

  zone_id = data.aws_route53_zone.route53_zone_theorchard_io_networking.zone_id
  name    = "statementdb.theorchard.io"
  type    = "CNAME"
  ttl     = 60
  records = ["statementdb.theorchard.com"]
}
