AWSTemplateFormatVersion: "2010-09-09"
Description: AWS Infrastructure Setup with EC2, ALB, Target Group, Apache HTTPD, NAT Gateway, and Dedicated Security Groups

Parameters:
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
  PublicSubnetACIDR:
    Type: String
    Default: "10.0.0.0/24"
  PublicSubnetCCIDR:
    Type: String
    Default: "10.0.1.0/24"
  PrivateSubnetACIDR:
    Type: String
    Default: "10.0.10.0/24"
  PrivateSubnetCCIDR:
    Type: String
    Default: "10.0.11.0/24"

Resources:
  # VPC
  WSVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      Tags:
        - Key: Name
          Value: ws-vpc

  # Internet Gateway
  WSIGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: ws-igw

  WSVPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref WSVPC
      InternetGatewayId: !Ref WSIGW

  # Public Subnets
  WSPublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PublicSubnetACIDR
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: "true"
      Tags:
        - Key: Name
          Value: ws-pub-a

  WSPublicSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PublicSubnetCCIDR
      AvailabilityZone: !Select [2, !GetAZs ""]
      MapPublicIpOnLaunch: "true"
      Tags:
        - Key: Name
          Value: ws-pub-c

  # Private Subnets
  WSPrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PrivateSubnetACIDR
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: ws-priv-a

  WSPrivateSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PrivateSubnetCCIDR
      AvailabilityZone: !Select [2, !GetAZs ""]
      Tags:
        - Key: Name
          Value: ws-priv-c

  # Elastic IP for NAT Gateway
  WSEIPA:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  WSEIPC:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  # NAT Gateway in Public Subnet A
  WSNATGatewayA:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt WSEIPA.AllocationId
      SubnetId: !Ref WSPublicSubnetA
      Tags:
        - Key: Name
          Value: ws-natgw-a

  WSNATGatewayC:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt WSEIPC.AllocationId
      SubnetId: !Ref WSPublicSubnetC
      Tags:
        - Key: Name
          Value: ws-natgw-c

  # Route Table for Public Subnets
  WSPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref WSVPC
      Tags:
        - Key: Name
          Value: ws-pub-rt

  # Route for Public Subnets to Internet Gateway
  WSPublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WSPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref WSIGW

  # Associate Public Subnets with Public Route Table
  WSPublicSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPublicSubnetA
      RouteTableId: !Ref WSPublicRouteTable

  WSPublicSubnetCRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPublicSubnetC
      RouteTableId: !Ref WSPublicRouteTable

  # Private Route Table for Private Subnet A
  WSPrivateRouteTableA:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref WSVPC
      Tags:
        - Key: Name
          Value: ws-priv-a-rt

  # Route for Private Subnet A to NAT Gateway
  WSPrivateRouteA:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WSPrivateRouteTableA
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref WSNATGatewayA

  # Associate Private Subnet A with Private Route Table A
  WSPrivateSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPrivateSubnetA
      RouteTableId: !Ref WSPrivateRouteTableA

  # Private Route Table for Private Subnet C
  WSPrivateRouteTableC:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref WSVPC
      Tags:
        - Key: Name
          Value: ws-priv-c-rt

  # Route for Private Subnet C to NAT Gateway
  WSPrivateRouteB:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WSPrivateRouteTableC
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref WSNATGatewayC

  # Associate Private Subnet C with Private Route Table C
  WSPrivateSubnetBRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPrivateSubnetC
      RouteTableId: !Ref WSPrivateRouteTableC

  # Security Group for App Servers
  AppServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow HTTP access to App Servers"
      VpcId: !Ref WSVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0 # Allow SSH access for debugging (restrict this in production)
      Tags:
        - Key: Name
          Value: app-server-sg

  # EC2 Instances (App Servers)
  AppServerA:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: ami-062cddb9d94dcf95d
      SubnetId: !Ref WSPrivateSubnetA
      SecurityGroupIds:
        - !Ref AppServerSecurityGroup
      Tags:
        - Key: Name
          Value: app-server-a
      UserData: !Base64 |
        #!/bin/bash
        sudo yum update -y
        sudo yum install -y httpd
        echo "app-server-a page" > /var/www/html/index.html
        sudo systemctl start httpd
        sudo systemctl enable httpd

  AppServerC:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: ami-062cddb9d94dcf95d
      SubnetId: !Ref WSPrivateSubnetC
      SecurityGroupIds:
        - !Ref AppServerSecurityGroup
      Tags:
        - Key: Name
          Value: app-server-b
      UserData: !Base64 |
        #!/bin/bash
        sudo yum update -y
        sudo yum install -y httpd
        echo "app-server-b page" > /var/www/html/index.html
        sudo systemctl start httpd
        sudo systemctl enable httpd

  # Target Group for ALB
  WSTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: ws-target-group
      Protocol: HTTP
      Port: "80"
      VpcId: !Ref WSVPC
      TargetType: instance
      HealthCheckProtocol: HTTP
      HealthCheckPort: "80"
      HealthCheckPath: /
      Matcher:
        HttpCode: "200"
      Targets: # Attach EC2 instances here
        - Id: !Ref AppServerA
          Port: 80
        - Id: !Ref AppServerC
          Port: 80

  # ALB
  WSALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: ws-alb
      Subnets:
        - Ref: WSPublicSubnetA
        - Ref: WSPublicSubnetC
      SecurityGroups:
        - !GetAtt ALBSecurityGroup.GroupId
      LoadBalancerAttributes:
        - Key: idle_timeout.timeout_seconds
          Value: "60"
      Scheme: internet-facing
      Type: application

  WSALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref WSTargetGroup
      LoadBalancerArn: !Ref WSALB
      Port: "80"
      Protocol: HTTP

  # ALB Security Group
  ALBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupDescription: "Allow HTTP traffic"
      VpcId: !Ref WSVPC
      GroupName: "ws-alb-sg"
      #inbound
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      #outbound
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: "ws-alb-sg"

Outputs:
  VPCId:
    Value: !Ref WSVPC
  PublicSubnetAId:
    Value: !Ref WSPublicSubnetA
  PublicSubnetBId:
    Value: !Ref WSPublicSubnetC
  PrivateSubnetAId:
    Value: !Ref WSPrivateSubnetA
  PrivateSubnetBId:
    Value: !Ref WSPrivateSubnetC
  LoadBalancerDNSName:
    Value: !GetAtt WSALB.DNSName