locals {
  apollo_app_secrets_list = [
    "AMPLITUDE_KEY",
    "APPLE_MUSICKIT_KEY",
    "DEEZER_CLIENT_ID",
    "DEEZER_CLIENT_SECRET",
    "GOOGLE_ANALYTICS_ID",
    "INTERCOM_APPID",
    "SENTRY_DSN",
    "SERVICE_ACCOUNT_SPOTIFY_CLIENT_ID",
    "SERVICE_ACCOUNT_SPOTIFY_CLIENT_SECRET",
    "SPLIT_IO_API_KEY",
    "SPOTIFY_CLIENT_SECRET",
    "YOUTUBE_API_KEY",
    "YOUTUBE_CLIENT_ID",
    "YOUTUBE_CLIENT_SECRET",
  ]

  apollo_app_common_secrets = {
    ADMINAPI_KEY = aws_secretsmanager_secret.common_secret["ADMINAPI_KEY"]
  }

  apollo_app_secrets_mapping = [
    for k, v in merge(aws_secretsmanager_secret.apollo_app_secret, local.apollo_app_common_secrets) :
    {
      name      = k,
      valueFrom = "arn:aws:secretsmanager:${var.aws_region_id}:${local.account_id}:secret:${v["name"]}"
    }
  ]

  apollo_app_env_vars = [
    {
      name  = "NODE_ENV",
      value = "production"
    },
    {
      name  = "DEBUG",
      value = "filtr*"
    },
    {
      name  = "APP_ENV",
      value = local.environment
    },
    {
      name  = "PORT",
      value = "8080"
    },
    {
      name  = "PRIVATEAPI_URI",
      value = "https://${module.domains[local.env_prefix]["traefik"]}"
    },
    {
      name  = "ADMINAPI_HOSTNAME",
      value = module.domains.dev["admin-api-proxy"]
    },
    {
      name  = "AUTH0_DIRECT_PING_INTERVAL",
      value = "240"
    },
    {
      name  = "AUTH0_PING_INTERVAL",
      value = "60"
    },
    {
      name  = "CDN_IMAGES_ROOT",
      value = "https://dhfsk7jl2g0km.cloudfront.net"
    },
    {
      name  = "FLAGS_ROOT",
      value = "https://${module.domains[local.env_prefix]["apolloapp-static"]}/static/flags-svg"
    },
    {
      name  = "STATIC_ROOT",
      value = "https://${module.domains[local.env_prefix]["apolloapp-static"]}/static"
    },
    {
      name  = "DEEZER_REDIRECT_URI",
      value = "https://${module.domains[local.env_prefix]["apolloapp"]}/_serviceaccounts/callback/deezer"
    },
    {
      name  = "SERVICE_ACCOUNT_SPOTIFY_REDIRECT_URI",
      value = "https://${module.domains[local.env_prefix]["apolloapp"]}/_serviceaccounts/callback/spotify"
    },
    {
      name  = "YOUTUBE_REDIRECT_URI",
      value = "https://${module.domains[local.env_prefix]["apolloapp"]}/_serviceaccounts/callback/youtube"
    },
    {
      name  = "APPLE_MUSICKIT_TEAM_ID",
      value = "PYHJN9Z6W2"
    },
    {
      name  = "APPLE_MUSICKIT_KEYID",
      value = "379HL9CZV5"
    },
    {
      name  = "SPOTIFY_CLIENT_ID",
      value = "c3a2bff1dba240e99af7826567abf96c"
    },
  ]
}

data "aws_ecr_repository" "apolloapp_ecr" {
  name     = "apolloapp"
  provider = aws.gdb-delphi-dev
}

resource "aws_secretsmanager_secret" "apollo_app_secret" {
  for_each = toset(local.apollo_app_secrets_list)

  name       = "${local.secrets_name_prefix}/apolloapp/${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"
    }
  )
}

module "apollo_app_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}-apolloapp"
  container_name  = "apolloapp"
  container_image = "${data.aws_ecr_repository.apolloapp_ecr.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 = data.aws_iam_role.standard_exec.arn
  exec_role_arn = data.aws_iam_role.standard_exec.arn

  env_vars = local.apollo_app_env_vars
  secrets  = local.apollo_app_secrets_mapping

  docker_labels = {
    "traefik.enable" = "false"
  }

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

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

module "apollo_app_service" {
  source = "../../../modules/ecs/services/service_taskless_v3"

  env_prefix    = local.env_prefix
  project       = "apolloapp"
  project_group = local.project_group

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

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

  task_definition_arn = module.apollo_app_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          = 8080
  url                     = module.domains[local.env_prefix]["apolloapp"]

  enable_ecs_managed_tags = true

  capacity_provider_strategy = {
    a = {
      base              = 1
      weight            = 2
      capacity_provider = "FARGATE_SPOT"
    },
    b = {
      base              = 0
      weight            = 1
      capacity_provider = "FARGATE"
    },
  }

  common_tags = merge(
    local.common_tags,
    {
      project                  = "Portal",
      service                  = "ECS",
      plat_env_project_service = "${local.aggregated_tag}_PRL_ECS"
      service_name             = "apollo-apolloapp"
    }
  )
}

resource "aws_s3_bucket" "apollo_static" {
  bucket        = "${local.env_prefix}-${local.project_group}-new-ui"
  force_destroy = true

  tags = merge(
    local.common_tags,
    {
      project                  = "Portal",
      service                  = "S3",
      plat_env_project_service = "${local.aggregated_tag}_PRL_S3"
    }
  )
}

resource "aws_s3_bucket_logging" "apollo_static" {
  bucket        = aws_s3_bucket.apollo_static.bucket
  target_bucket = data.aws_s3_bucket.logs_bucket.id
  target_prefix = "s3/${local.name_prefix}/apollo-frontend/"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "apollo_static" {
  bucket = aws_s3_bucket.apollo_static.bucket
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_s3_bucket_cors_configuration" "apollo_static" {
  bucket = aws_s3_bucket.apollo_static.bucket
  cors_rule {
    allowed_methods = ["GET", "HEAD", "DELETE", "PUT", "POST"]
    allowed_origins = ["https://${module.domains[local.env_prefix]["apolloapp"]}"]
  }
}

resource "aws_s3_bucket_ownership_controls" "apollo_static" {
  bucket = aws_s3_bucket.apollo_static.id

  rule {
    object_ownership = "BucketOwnerEnforced"
  }
}

resource "aws_s3_bucket_policy" "apollo_static" {
  bucket = aws_s3_bucket.apollo_static.id
  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSSLRequestsOnly",
      "Effect": "Deny",
      "Principal": {
        "AWS": "*"
      },
      "Action": "s3:*",
      "Resource": [
        "${aws_s3_bucket.apollo_static.arn}/*",
        "${aws_s3_bucket.apollo_static.arn}"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    },
    {
      "Sid": "OnlyCloudfrontReadAccess",
      "Principal": {
        "AWS": "${aws_cloudfront_origin_access_identity.apollo_static.iam_arn}"
      },
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "${aws_s3_bucket.apollo_static.arn}/*"
    }
  ]
}
POLICY
}

resource "aws_cloudfront_origin_access_identity" "apollo_static" {
  comment = "Cloudfront access identity for accessing bucket ${aws_s3_bucket.apollo_static.id}"
}

resource "aws_cloudfront_distribution" "apollo_static" {
  enabled      = true
  price_class  = "PriceClass_100"
  http_version = "http2"
  aliases      = [module.domains[local.env_prefix]["apolloapp-static"]]
  web_acl_id   = data.aws_wafv2_web_acl.ioc_web_acl_global.arn

  logging_config {
    include_cookies = false
    bucket          = data.aws_s3_bucket.logs_bucket.bucket_domain_name
    prefix          = "cf/${local.name_prefix}-main"
  }

  origin {
    origin_id   = "origin-bucket-${aws_s3_bucket.apollo_static.id}"
    domain_name = aws_s3_bucket.apollo_static.bucket_domain_name

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.apollo_static.cloudfront_access_identity_path
    }
  }

  default_root_object = "index.html"
  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "origin-bucket-${aws_s3_bucket.apollo_static.id}"
    min_ttl          = "43200"  // 12 hours
    default_ttl      = "86400"  // 1 day
    max_ttl          = "604800" // 1 week
    // This redirects any HTTP request to HTTPS. Security first!
    viewer_protocol_policy = "redirect-to-https"
    compress               = true

    forwarded_values {
      query_string = false
      headers      = ["Origin"]
      cookies {
        forward = "none"
      }
    }
  }

  custom_error_response {
    error_caching_min_ttl = 43200 // 12 hours
    error_code            = 404
    response_code         = 200
    response_page_path    = "/index.html"
  }

  custom_error_response {
    error_caching_min_ttl = 43200 // 12 hours
    error_code            = 403
    response_code         = 200
    response_page_path    = "/index.html"
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    acm_certificate_arn      = data.aws_acm_certificate.wildcard_filtr_apollo_cert.arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2021"
  }

  tags = merge(
    local.common_tags,
    {
      project                  = "Portal",
      service                  = "Cloudfront",
      plat_env_project_service = "${local.aggregated_tag}_PRL_CFR"
    }
  )
}

resource "aws_route53_record" "apollo_apolloapp_record" {
  zone_id = data.aws_route53_zone.apollo_stream_zone.zone_id
  name    = module.domains[local.env_prefix]["apolloapp"]
  type    = "A"
  alias {
    name                   = data.aws_lb.external_alb.dns_name
    zone_id                = data.aws_lb.external_alb.zone_id
    evaluate_target_health = false
  }

  provider = aws.gdb-delphi-dev
}

resource "aws_route53_record" "apollo_apolloapp_static_record" {
  zone_id = data.aws_route53_zone.apollo_stream_zone.zone_id
  name    = module.domains[local.env_prefix]["apolloapp-static"]
  type    = "A"
  alias {
    name                   = aws_cloudfront_distribution.apollo_static.domain_name
    zone_id                = aws_cloudfront_distribution.apollo_static.hosted_zone_id
    evaluate_target_health = false
  }

  provider = aws.gdb-delphi-dev
}
