locals {
  notifications_secrets_list = [
    "AMPLITUDE_API_KEY",
    "CELERY_BROKER_URL",     # amqps://user:password@host:port/host
    "CELERY_RESULT_BACKEND", # currently is Redis URL, we plan to migrate to PostgreSQL
    "MAIL_PASSWORD",
    "SENTRY_DSN",
    "SESSION_SECRET",
  ]

  notifications_secrets_mapping_list = [
    for k, v in aws_secretsmanager_secret.notifications_secret :
    {
      name      = k,
      valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:${v["name"]}"
    }
  ]

  notifications_secrets_combined = concat(
    local.notifications_secrets_mapping_list,
    [
      {
        name      = "PGDB_PASS",
        valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:core/${local.env_prefix}/notifications/pg/user:password::"
      },
      {
        name      = "PGDB_USER",
        valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:core/${local.env_prefix}/notifications/pg/user:username::"
      },
      {
        name      = "PGDB_HOST",
        valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:core/${local.env_prefix}/notifications/pg/user:host::"
      },
    ]
  )

  notifications_env_vars = [
    {
      name  = "FLASK_ENV",
      value = local.environment
    },
    {
      name  = "LOGLEVEL",
      value = "INFO"
    },
    {
      name  = "JSON_LOGS",
      value = 1
    },
    {
      name  = "MAIL_SERVER",
      value = "email-smtp.us-east-1.amazonaws.com"
    },
    {
      name  = "MAIL_PORT",
      value = "2587"
    },
    {
      name  = "MAIL_USE_TLS",
      value = "True"
    },
    {
      name  = "MAIL_USERNAME",
      value = "AKIAUWVLCK3R5RLQFL6X"
    },
    {
      name  = "MAIL_DEFAULT_SENDER",
      value = "product-support@sonymusic-pde.com"
    },
    {
      name  = "ATLAS_LOGIN_URL",
      value = "https://${module.domains[local.env_prefix]["atlas-um"]}/usm/login"
    },
    {
      name  = "ATLAS_LOGOUT_URL",
      value = "https://${module.domains[local.env_prefix]["atlas-um"]}/usm/logout"
    },
    {
      name  = "ATLAS_REFRESH_TOKEN_URL",
      value = "https://${module.domains[local.env_prefix]["atlas-um"]}/usm/token/refresh"
    },
    {
      name  = "ATLAS_PUBLIC_KEY_URL",
      value = "https://${module.domains[local.env_prefix]["atlas-um-static"]}/pem/public.pem"
    },
    {
      name  = "PGDB_NAME",
      value = "notifications_${local.env_prefix}"
    },
    {
      name  = "MEDIA_BUCKET_NAME",
      value = data.aws_s3_bucket.static_notifications_s3_bucket.bucket
    },
    {
      name  = "MEDIA_URL",
      value = "https://${module.domains[local.env_prefix]["static-notifications"]}/"
    },
    {
      name  = "STATIC_URL",
      value = "https://${module.domains[local.env_prefix]["static-notifications"]}"
    },
    {
      name = "ALLOWED_HOSTS",
      value = join(",",
        [
          module.domains[local.env_prefix]["notifications-api"],
        ]
      )
    },
  ]

  notifications_celery_tasks = {
    celery_worker = {
      entrypoint = ["/opt/venv/bin/celery", "-A", "core_notifications.celery_worker.celery", "worker", "--loglevel=info"]
    },
    celery_beat = {
      entrypoint = ["/opt/venv/bin/celery", "-A", "core_notifications.celery_worker.celery", "beat", "--loglevel=info"]
    },
  }
}

data "aws_ecr_repository" "notifications" {
  name     = "core/notifications"
  provider = aws.gdb-core-dev
}

data "aws_ecr_repository" "notifications_sqitch" {
  name     = "core/notifications-sqitch"
  provider = aws.gdb-core-dev
}

module "notifications_ecs_role" {
  source = "../../../modules/iam/roles/ecs_task_role"

  enable_default_role = false
  name_prefix         = local.name_prefix
  name                = "notifications_ecs_role"

  policies_list = [
    data.aws_iam_policy.logging_policy.arn,
    data.aws_iam_policy.secrets_deployment_ro.arn,
    data.aws_iam_policy.s3_static_notifications_rw_policy.arn,
  ]

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
    }
  )
}

resource "aws_secretsmanager_secret" "notifications_secret" {
  for_each = toset(local.notifications_secrets_list)

  name       = "${local.secrets_name_prefix}/notifications/${each.value}"
  kms_key_id = data.aws_kms_key.secrets_general_key.id

  tags = merge(
    local.common_tags,
    {
      project                  = "Infrastructure",
      service                  = "Secrets Manager",
      plat_env_project_service = "${local.aggregated_tag}_INFRA_SCRT"
    }
  )
}

resource "aws_route53_record" "notifications_api_record" {
  provider = aws.gdb-core-dev
  zone_id  = data.aws_route53_zone.atlas_stream_domain.id
  name     = module.domains[local.env_prefix]["notifications-api"]
  type     = "A"

  alias {
    name                   = data.aws_lb.external_alb.dns_name
    zone_id                = data.aws_lb.external_alb.zone_id
    evaluate_target_health = false
  }
}

module "notifications_api_task_def" {
  source = "../../../modules/ecs/tasks/fargate_v3"

  env_prefix      = local.env_prefix
  project_group   = local.project_group
  family          = "${local.env_prefix}-${local.project_group}-notifications"
  container_name  = "notifications"
  container_image = "${data.aws_ecr_repository.notifications.repository_url}:${local.docker_image_env_tag[local.env_prefix]}"
  cpu             = 1024
  memory          = 2048

  awslogs_retention = module.cloudwatch_logs_retention_by_env[local.env_prefix]

  task_role_arn = module.notifications_ecs_role.role.arn
  exec_role_arn = data.aws_iam_role.standard_exec.arn

  env_vars = local.notifications_env_vars
  secrets  = local.notifications_secrets_combined

  datadog_enabled    = true
  dd_apm_enabled     = true
  dd_container_image = "public.ecr.aws/datadog/agent:latest"
  dd_awslogs_group   = aws_cloudwatch_log_group.datadog-agent.name

  dd_secrets = [
    {
      name      = "DD_API_KEY",
      valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:${local.secrets_name_prefix}/common/DD_API_KEY"
    }
  ]

  dd_env_vars = [
    {
      name  = "DD_APM_IGNORE_RESOURCES",
      value = "GET /health"
    },
    {
      name  = "DD_TAGS",
      value = "service:core-atlas-notifications application_family:atlas"
    },
  ]

  port_mappings = [
    {
      containerPort = 8000
      hostPort      = 8000
      protocol      = "tcp"
    }
  ]

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
      servicename              = "${local.project_group}-notifications"
    }
  )
}

module "notifications_api_service" {
  source = "../../../modules/ecs/services/service_taskless_v2"

  env_prefix    = local.env_prefix
  project       = "notifications"
  project_group = local.project_group

  cluster_arn   = data.aws_ecs_cluster.main.arn
  desired_count = 2

  security_groups = [data.aws_security_group.ecs.id]
  subnets         = data.aws_subnets.private_subnets.ids
  vpc_id          = data.aws_vpc.main.id

  task_definition_arn = module.notifications_api_task_def.arn

  alb_enabled             = true
  https_listener_arn      = data.aws_lb_listener.external_https_listener.arn
  tg_health_check_path    = "/health"
  tg_health_check_matcher = "200"
  container_port          = 8000
  url                     = module.domains[local.env_prefix]["notifications-api"]

  enable_ecs_managed_tags = true

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
      servicename              = "${local.project_group}-notifications"
    }
  )
}

module "notifications_api_appautoscaling" {
  source = "../../../modules/appautoscaling/ecs"

  env_prefix           = local.env_prefix
  max_capacity         = 10
  min_capacity         = 1
  project              = "notifications"
  project_group        = local.project_group
  resource_id          = "service/${data.aws_ecs_cluster.main.cluster_name}/${module.notifications_api_service.ecs_service.name}"
  upscaling_adjustment = 1
}

resource "aws_cloudwatch_metric_alarm" "notifications_api_high_usage" {
  alarm_name          = "${local.name_prefix}-notifications-api_high_usage"
  alarm_description   = "Memory/CPU usage is higher than threshold."
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = 1
  threshold           = 1
  actions_enabled     = true
  alarm_actions       = [module.notifications_api_appautoscaling.scaling_up_policy.arn]

  metric_query {
    id          = "check_thresholds"
    expression  = "(cpu >= 10 OR memory >= 15)"
    label       = "CPU and Memory utilization limits"
    return_data = true
  }

  metric_query {
    id          = "cpu"
    return_data = false

    metric {
      metric_name = "CPUUtilization"
      namespace   = "AWS/ECS"
      period      = "60"
      stat        = "Maximum"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_api_service.ecs_service.name
      }
    }
  }

  metric_query {
    id          = "memory"
    return_data = false

    metric {
      metric_name = "MemoryUtilization"
      namespace   = "AWS/ECS"
      period      = "60"
      stat        = "Maximum"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_api_service.ecs_service.name
      }
    }
  }
}

resource "aws_cloudwatch_metric_alarm" "notifications_api_low_usage" {
  alarm_name          = "${local.name_prefix}-notifications-api_low_usage"
  alarm_description   = "Memory/CPU usage is lower than threshold."
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = 3
  threshold           = 1
  actions_enabled     = true
  alarm_actions       = [module.notifications_api_appautoscaling.scaling_down_policy.arn]

  metric_query {
    id          = "check_thresholds"
    expression  = "(cpu < 10 AND memory < 15)"
    label       = "CPU and Memory utilization limits"
    return_data = true
  }

  metric_query {
    id          = "cpu"
    return_data = false

    metric {
      metric_name = "CPUUtilization"
      namespace   = "AWS/ECS"
      period      = "180"
      stat        = "Average"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_api_service.ecs_service.name
      }
    }
  }

  metric_query {
    id          = "memory"
    return_data = false

    metric {
      metric_name = "MemoryUtilization"
      namespace   = "AWS/ECS"
      period      = "180"
      stat        = "Average"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_api_service.ecs_service.name
      }
    }
  }
}

module "notifications_api_sqitch_task_def" {
  source = "../../../modules/ecs/tasks/fargate_v3"

  env_prefix      = local.env_prefix
  project_group   = local.project_group
  family          = "${local.env_prefix}-${local.project_group}-notifications-sqitch"
  container_name  = "notifications-sqitch"
  container_image = "${data.aws_ecr_repository.notifications_sqitch.repository_url}:${local.docker_image_env_tag[local.env_prefix]}"
  cpu             = 512
  memory          = 1024

  awslogs_retention = module.cloudwatch_logs_retention_by_env[local.env_prefix]

  task_role_arn = data.aws_iam_role.standard_exec.arn
  exec_role_arn = data.aws_iam_role.standard_exec.arn

  env_vars = [
    {
      name  = "PGDB_NAME",
      value = "notifications_${local.env_prefix}"
    },
  ]
  secrets = [
    {
      name      = "PGDB_PASS",
      valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:maintenance/common/core/${local.env_prefix}/notifications_owner:password::"
    },
    {
      name      = "PGDB_USER",
      valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:maintenance/common/core/${local.env_prefix}/notifications_owner:username::"
    },
    {
      name      = "PGDB_HOST",
      valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:maintenance/common/core/${local.env_prefix}/notifications_owner:host::"
    },
  ]

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
    }
  )
}

resource "aws_cloudwatch_log_group" "notifications_celery_log_group" {
  name              = "/ecs/${local.name_prefix}-notifications-celery"
  retention_in_days = module.cloudwatch_logs_retention_by_env[local.env_prefix]
  tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "CloudWatch",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_CW"
    }
  )
}

module "notifications_celery_task_def" {
  for_each = local.notifications_celery_tasks
  source   = "../../../modules/ecs/tasks/fargate_v3"

  env_prefix      = local.env_prefix
  project_group   = local.project_group
  family          = "${local.env_prefix}-${local.project_group}-${each.key}"
  container_name  = "notifications"
  container_image = "${data.aws_ecr_repository.notifications.repository_url}:${local.docker_image_env_tag[local.env_prefix]}"
  cpu             = 1024
  memory          = 2048

  awslogs_create_group = false
  awslogs_group_name   = aws_cloudwatch_log_group.notifications_celery_log_group.name

  entrypoint = each.value.entrypoint

  task_role_arn = module.notifications_ecs_role.role.arn
  exec_role_arn = data.aws_iam_role.standard_exec.arn

  env_vars = local.notifications_env_vars
  secrets  = local.notifications_secrets_combined

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
    }
  )
}

module "notifications_celery_service" {
  for_each = local.notifications_celery_tasks
  source   = "../../../modules/ecs/services/service_taskless_v2"

  env_prefix    = local.env_prefix
  project       = "notifications-${each.key}"
  project_group = local.project_group

  cluster_arn   = data.aws_ecs_cluster.main.arn
  desired_count = 1
  min_percent   = 0
  max_percent   = 100

  security_groups = [data.aws_security_group.ecs.id]
  subnets         = data.aws_subnets.private_subnets.ids
  vpc_id          = data.aws_vpc.main.id

  task_definition_arn = module.notifications_celery_task_def[each.key].arn

  enable_ecs_managed_tags = true

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
    }
  )
}

module "notifications_celery_worker_appautoscaling" {
  source = "../../../modules/appautoscaling/ecs"

  env_prefix             = local.env_prefix
  max_capacity           = 15
  min_capacity           = 1
  project                = "notifications-celery_worker"
  project_group          = local.project_group
  resource_id            = "service/${data.aws_ecs_cluster.main.cluster_name}/${module.notifications_celery_service["celery_worker"].ecs_service.name}"
  upscaling_adjustment   = 2
  downscaling_adjustment = -1
}

resource "aws_cloudwatch_metric_alarm" "notifications_celery_worker_high_usage" {
  alarm_name          = "${local.name_prefix}-notifications-celery_worker_high_usage"
  alarm_description   = "Memory/CPU usage is higher than threshold."
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = 1
  threshold           = 1
  actions_enabled     = true
  alarm_actions       = [module.notifications_celery_worker_appautoscaling.scaling_up_policy.arn]

  metric_query {
    id          = "check_thresholds"
    expression  = "(cpu >= 40 OR memory >= 60)"
    label       = "CPU and Memory utilization limits"
    return_data = true
  }

  metric_query {
    id          = "cpu"
    return_data = false

    metric {
      metric_name = "CPUUtilization"
      namespace   = "AWS/ECS"
      period      = "60"
      stat        = "Maximum"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_celery_service["celery_worker"].ecs_service.name
      }
    }
  }

  metric_query {
    id          = "memory"
    return_data = false

    metric {
      metric_name = "MemoryUtilization"
      namespace   = "AWS/ECS"
      period      = "60"
      stat        = "Maximum"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_celery_service["celery_worker"].ecs_service.name
      }
    }
  }
}

resource "aws_cloudwatch_metric_alarm" "notifications_celery_service_low_usage" {
  alarm_name          = "${local.name_prefix}-notifications-celery_worker_low_usage"
  alarm_description   = "Memory/CPU usage is lower than threshold."
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = 3
  threshold           = 1
  actions_enabled     = true
  alarm_actions       = [module.notifications_celery_worker_appautoscaling.scaling_down_policy.arn]

  metric_query {
    id          = "check_thresholds"
    expression  = "(cpu < 30 AND memory < 50)"
    label       = "CPU and Memory utilization limits"
    return_data = true
  }

  metric_query {
    id          = "cpu"
    return_data = false

    metric {
      metric_name = "CPUUtilization"
      namespace   = "AWS/ECS"
      period      = "180"
      stat        = "Average"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_celery_service["celery_worker"].ecs_service.name
      }
    }
  }

  metric_query {
    id          = "memory"
    return_data = false

    metric {
      metric_name = "MemoryUtilization"
      namespace   = "AWS/ECS"
      period      = "180"
      stat        = "Average"

      dimensions = {
        ClusterName = data.aws_ecs_cluster.main.cluster_name
        ServiceName = module.notifications_celery_service["celery_worker"].ecs_service.name
      }
    }
  }
}

module "notifications_celery_flower_task_def" {
  source = "../../../modules/ecs/tasks/fargate_v3"

  env_prefix      = local.env_prefix
  project_group   = local.project_group
  family          = "${local.env_prefix}-${local.project_group}-notifications_celery_flower"
  container_name  = "notifications"
  container_image = "${data.aws_ecr_repository.notifications.repository_url}:${local.docker_image_env_tag[local.env_prefix]}"
  cpu             = 1024
  memory          = 2048

  awslogs_create_group = false
  awslogs_group_name   = aws_cloudwatch_log_group.notifications_celery_log_group.name

  entrypoint = ["/opt/venv/bin/celery", "-A", "core_notifications.celery_worker.celery", "flower", "--basic_auth=flower_usr:G@rd3n1@$"]

  task_role_arn = module.notifications_ecs_role.role.arn
  exec_role_arn = data.aws_iam_role.standard_exec.arn

  env_vars = local.notifications_env_vars
  secrets  = local.notifications_secrets_combined

  port_mappings = [
    {
      containerPort = 5555
      hostPort      = 5555
      protocol      = "tcp"
    }
  ]

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
    }
  )
}

module "notifications_celery_flower_service" {
  source = "../../../modules/ecs/services/service_taskless_v2"

  env_prefix    = local.env_prefix
  project       = "notifications-celery_flower"
  project_group = local.project_group

  cluster_arn   = data.aws_ecs_cluster.main.arn
  desired_count = 1

  security_groups = [data.aws_security_group.ecs.id]
  subnets         = data.aws_subnets.private_subnets.ids
  vpc_id          = data.aws_vpc.main.id

  task_definition_arn = module.notifications_celery_flower_task_def.arn

  alb_enabled             = true
  https_listener_arn      = data.aws_lb_listener.internal_https_listener.arn
  tg_health_check_path    = "/healthcheck"
  tg_health_check_matcher = "200"
  container_port          = 5555
  url                     = module.domains[local.env_prefix]["notifications-celery-flower"]
  container_name          = "notifications"

  enable_ecs_managed_tags = true

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Notifications",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_NOTIF_ECS"
    }
  )
}
