#
# AWS
# Websocket server process.
#

provider "aws" {
  region = "us-west-2"
}

variable "network_name" {
}

variable "fleet_name" {
}

variable "name" {
  type    = string
  default = "cloud_websocket"
}

variable "ami" {
  type = string
}

variable "instance_type" {
  type    = string
  default = "t2.micro"
}

variable "key_name" {
  type = string
}

variable "cloud_websocket_elb_certificate_arn" {
  type = string
}

variable "pm2_memory_high" {
  description = "Cgroup MemoryHigh for pm2-ubuntu.service (reclaim pressure). Systemd syntax: '75%' of RAM, '24G', or 'infinity'."
  type        = string
  default     = "75%"
}

variable "pm2_memory_max" {
  description = "Cgroup MemoryMax for pm2-ubuntu.service (cgroup OOM threshold). Systemd syntax: '85%' of RAM, '28G', or 'infinity'."
  type        = string
  default     = "85%"
}


locals {
  cloud_websocket_server_name = "${var.network_name}-${var.fleet_name}-cloud-websocket"
  network_fleet_name          = "${var.network_name}_${var.fleet_name}"
}


resource "aws_instance" "cloud_websocket" {
  ami             = var.ami
  instance_type   = var.instance_type
  placement_group = "${local.network_fleet_name}_placement_group"
  key_name        = var.key_name
  security_groups = [
    aws_security_group.cloud_websocket_security_group.name,

    # Developer: SSH access security group
    "[Bigscreen] SSH Server Access"
  ]

  tags = {
    Name = "[${local.network_fleet_name}] ${local.cloud_websocket_server_name}"
  }

  root_block_device {
    volume_type = "gp2"
    volume_size = 128
    encrypted   = true
  }

  # nginx config
  provisioner "file" {
    source      = "/home/ubuntu/networks/${var.network_name}/${var.fleet_name}/config/${var.network_name}_${var.fleet_name}_cloud_websocket_server.nginx.conf"
    destination = "/home/ubuntu/default.nginx.conf"
  }

  provisioner "remote-exec" {
    inline = [
      # Install Node.js 24
      "curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -",
      "sudo apt-get install -y nodejs",


      # Install PM2
      "sudo npm install -g pm2",

      # Register PM2 as a systemd service (pm2-ubuntu.service) with cgroup memory
      # limits. Without this, Jenkins' "pm2 start" over SSH leaves PM2 running in
      # the SSH session scope — a worker memory blowup then triggers a global OOM
      # that takes the whole instance offline. As a system service with MemoryMax,
      # the OOM kill is scoped to PM2's children and sshd/networkd stay alive.
      "sudo mkdir -p /etc/systemd/system/pm2-ubuntu.service.d",
      "printf '[Service]\\nMemoryHigh=%s\\nMemoryMax=%s\\n' '${var.pm2_memory_high}' '${var.pm2_memory_max}' | sudo tee /etc/systemd/system/pm2-ubuntu.service.d/override.conf > /dev/null",
      "sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ubuntu --hp /home/ubuntu",

      # Install nginx (if not already installed)
      "sudo apt-get update",
      "sudo apt-get install -y nginx",

      # Configure nginx
      "sudo cp /home/ubuntu/default.nginx.conf /etc/nginx/sites-enabled/default",
      "sudo service nginx restart",
    ]
  }

  connection {
    type        = "ssh"
    host        = self.public_dns
    user        = "ubuntu"
    private_key = file("/home/ubuntu/networks/${var.network_name}/${var.fleet_name}/aws/${var.key_name}.pem")
    timeout     = "5m"
  }
}


# Security group for the cloud_websocket server itself.
resource "aws_security_group" "cloud_websocket_security_group" {
  name        = "${local.cloud_websocket_server_name}_security_group"
  description = "${local.cloud_websocket_server_name} Internal"
  vpc_id      = "vpc-6284a71b"

  # ELB forwarding along port 80 for https for the cloud_websocket server.
  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.cloud_websocket_elb_security_group.id]
  }

  # Jenkins SSH access
  ingress {
    from_port       = 22
    to_port         = 22
    protocol        = "tcp"
    security_groups = ["sg-0577fa74bb0447c98"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "[${local.network_fleet_name}] ${local.cloud_websocket_server_name}_security_group"
  }
}


#
# cloud_websocket Server ELB
#

# Security Group for the cloud_websocket Server ELB
resource "aws_security_group" "cloud_websocket_elb_security_group" {
  name        = "${local.cloud_websocket_server_name}_elb_security_group"
  description = "${local.cloud_websocket_server_name} ELB"
  vpc_id      = "vpc-6284a71b"

  ingress {
    from_port = 443
    to_port   = 443
    protocol  = "tcp"
    # Please restrict your ingress to only necessary IPs and ports.
    # Opening to 0.0.0.0/0 can lead to security vulnerabilities.
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "[${local.network_fleet_name}] ${local.cloud_websocket_server_name}_elb_security_group"
  }
}


# cloud_websocket Server API ELB, sending data
resource "aws_lb" "cloud_websocket_elb" {
  name               = "${local.cloud_websocket_server_name}-elb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.cloud_websocket_elb_security_group.id]
  subnets            = ["subnet-08218e43", "subnet-9e79f4e7", "subnet-bc5736e6", "subnet-41185f69"]

  enable_deletion_protection = var.network_name == "main"
}


resource "aws_lb_target_group" "cloud_websocket_target" {
  name     = "${local.cloud_websocket_server_name}-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = "vpc-6284a71b"
}


resource "aws_lb_target_group_attachment" "test" {
  target_group_arn = aws_lb_target_group.cloud_websocket_target.arn
  target_id        = aws_instance.cloud_websocket.id
  port             = 80
}


resource "aws_lb_listener" "cloud_websocket_elb" {
  load_balancer_arn = aws_lb.cloud_websocket_elb.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"
  certificate_arn   = var.cloud_websocket_elb_certificate_arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.cloud_websocket_target.arn
  }
}


#
# Outputs - DNS addresses for the server, and the ELBs
#
output "cloud_websocket_dns" {
  value = aws_instance.cloud_websocket.public_dns
}

output "cloud_websocket_elb_dns" {
  value = aws_lb.cloud_websocket_elb.dns_name
}

output "security_group_id" {
  value = aws_security_group.cloud_websocket_security_group.id
}