AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create EC2 instance with code-server'

Parameters:
  InstanceType:
    Type: String
    Description: EC2 instance type
    Default: m6i.large
    AllowedValues:
      - t3.small
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - c6i.large
      - c6i.xlarge
      - c6i.2xlarge
      - c6i.4xlarge
      - c6i.8xlarge
      - c6a.large
      - c6a.xlarge  
      - c6a.2xlarge
      - c6a.4xlarge
      - c6a.8xlarge
      - c6g.large
      - c6g.xlarge
      - c6g.2xlarge
      - c6g.4xlarge
      - c6g.8xlarge
      - m6i.large
      - m6i.xlarge
      - m6i.2xlarge
      - m6i.4xlarge
      - m6i.8xlarge
      - m6a.large
      - m6a.xlarge
      - m6a.2xlarge
      - m6a.4xlarge
      - m6a.8xlarge
      - m6g.large
      - m6g.xlarge
      - m6g.2xlarge
      - m6g.4xlarge
      - m6g.8xlarge
    ConstraintDescription: Must be a valid EC2 instance type.

  AmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
    Description: The ID of the AMI to use for the EC2 instance

  SysPassword:
    Type: String
    Description: vscode-server system password
    NoEcho: true
    MinLength: 8
    MaxLength: 41
    AllowedPattern: '[a-zA-Z0-9!@#$%^&*()_+=-]*'
    ConstraintDescription: Must contain only alphanumeric and special characters.

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: CodeServer-VPC

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: CodeServer-IGW

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select 
        - 0
        - !GetAZs ''
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: CodeServer-Public-Subnet

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: CodeServer-Public-RT

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for code-server EC2 instance
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8082
          ToPort: 8082
          CidrIp: 0.0.0.0/0

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      SecurityGroupIds: 
        - !Ref EC2SecurityGroup
      SubnetId: !Ref PublicSubnet
      ImageId: !Ref AmiId
      UserData: 
        Fn::Base64: !Sub |
          #!/bin/bash

          # 检测包管理器和安装必要软件
          install_dependencies() {
              if command -v yum >/dev/null 2>&1; then
                  # Amazon Linux 2, Amazon Linux 2023, CentOS
                  sudo yum update -y
                  sudo yum install -y docker curl tar
                  sudo systemctl start docker
                  sudo systemctl enable docker
                  # Amazon Linux 2023 可能需要额外步骤
                  if grep -q "Amazon Linux 2023" /etc/os-release; then
                        sudo dnf install -y docker
                        sudo systemctl start docker
                        sudo systemctl enable docker
                        sudo usermod -aG docker ec2-user
                  fi
              elif command -v apt-get >/dev/null 2>&1; then
                  # Ubuntu
                  sudo apt-get update
                  sudo apt-get install -y docker.io curl tar
                  sudo systemctl start docker
                  sudo systemctl enable docker
                  sudo usermod -aG docker ubuntu
              else
                  echo "Unsupported package manager"
                  exit 1
              fi
          }

          # 检查 Docker 服务状态
          check_docker() {
              if ! systemctl is-active --quiet docker; then
                  echo "Starting Docker service..."
                  sudo systemctl start docker
              fi
          }

          # 获取当前用户
          CURRENT_USER=$(whoami)

          # 安装依赖
          install_dependencies

          # 检测系统架构
          ARCH=$(uname -m)
          echo "Detecting system architecture..."

          # 创建临时目录
          mkdir -p temp_dir
          # 下载和安装 code-server
          echo "Downloading code-server..."
          case $(uname -m) in
              x86_64)
                  curl -fsSL "https://d2ejh5ecpm65gx.cloudfront.net/code-server-amd64.tar.gz" -o code-server.tar.gz
                  ;;
              aarch64|arm64)
                  curl -fsSL "https://d2ejh5ecpm65gx.cloudfront.net/code-server-arm64.tar.gz" -o code-server.tar.gz
                  ;;
              *)
                  echo "Unsupported architecture: $(uname -m)"
                  rm -rf temp_dir
                  exit 1
                  ;;
          esac

          # 检查下载是否成功
          if [ ! -f code-server.tar.gz ]; then
              echo "Failed to download code-server"
              rm -rf temp_dir
              exit 1
          fi

          # 解压镜像文件
          echo "Extracting Docker image..."
          tar -xzf code-server.tar.gz -C temp_dir
          if [ $? -ne 0 ]; then
              echo "Failed to extract archive"
              rm -rf temp_dir code-server.tar.gz
              exit 1
          fi

          # 导入 Docker 镜像
          echo "Loading Docker image..."
          sudo tar -cC temp_dir . | sudo docker load

          # 清理临时文件
          rm -rf temp_dir code-server.tar.gz

          # 停止并删除已存在的容器（如果存在）
          sudo docker rm -f code-server 2>/dev/null || true

          # 运行容器
          echo "Starting code-server container..."
          sudo docker run -d \
              --name code-server \
              -p 8082:8080 \
              -e "PASSWORD=${SysPassword}" \
              codercom/code-server:latest

          # 检查容器状态
          echo "Checking container status..."
          sleep 3
          if sudo docker ps | grep -q code-server; then
              echo "Code-server is running successfully at http://localhost:8082"
          else
              echo "Failed to start code-server container"
              sudo docker logs code-server
              exit 1
          fi

          # 等待 Docker 组更新生效
          if [ -n "$SUDO_USER" ]; then
              echo "Please log out and log back in for Docker group changes to take effect"
          fi

      Tags:
        - Key: Name
          Value: vscode-server

Outputs:
  CodeServerUrl:
    Description: URL to access code-server
    Value: !Sub http://${EC2Instance.PublicIp}:8082
