package lbc

import (
	"github.com/awslabs/eksdemo/pkg/application"
	"github.com/awslabs/eksdemo/pkg/cmd"
	"github.com/awslabs/eksdemo/pkg/installer"
	"github.com/awslabs/eksdemo/pkg/resource"
	"github.com/awslabs/eksdemo/pkg/resource/irsa"
	"github.com/awslabs/eksdemo/pkg/template"
)

// Docs:    https://kubernetes-sigs.github.io/aws-load-balancer-controller/
// GitHub:  https://github.com/kubernetes-sigs/aws-load-balancer-controller
// Helm:    https://github.com/aws/eks-charts/tree/master/stable/aws-load-balancer-controller
// Repo:    https://gallery.ecr.aws/eks/aws-load-balancer-controller
// Version: Latest is v2.9.0 (as of 10/2/24)

func NewApp() *application.Application {
	options, flags := newOptions()

	return &application.Application{
		Command: cmd.Command{
			Name:        "aws-lb-controller",
			Description: "AWS Load Balancer Controller",
			Aliases:     []string{"aws-lb", "awslb"},
		},

		Dependencies: []*resource.Resource{
			irsa.NewResourceWithOptions(&irsa.IrsaOptions{
				CommonOptions: resource.CommonOptions{
					Name: "aws-lb-controller-irsa",
				},
				PolicyType: irsa.PolicyDocument,
				PolicyDocTemplate: &template.TextTemplate{
					Template: policyDocument,
				},
			}),
		},

		Flags: flags,

		Installer: &installer.HelmInstaller{
			ChartName:     "aws-load-balancer-controller",
			ReleaseName:   "aws-lb-controller",
			RepositoryURL: "https://aws.github.io/eks-charts",
			ValuesTemplate: &template.TextTemplate{
				Template: valuesTemplate,
			},
		},

		Options: options,
	}
}

// https://github.com/kubernetes-sigs/aws-load-balancer-controller/blob/main/docs/install/iam_policy.json
const policyDocument = `
Version: '2012-10-17'
Statement:
- Effect: Allow
  Action:
  - iam:CreateServiceLinkedRole
  Resource: "*"
  Condition:
    StringEquals:
      iam:AWSServiceName: elasticloadbalancing.amazonaws.com
- Effect: Allow
  Action:
  - ec2:DescribeAccountAttributes
  - ec2:DescribeAddresses
  - ec2:DescribeAvailabilityZones
  - ec2:DescribeInternetGateways
  - ec2:DescribeVpcs
  - ec2:DescribeVpcPeeringConnections
  - ec2:DescribeSubnets
  - ec2:DescribeSecurityGroups
  - ec2:DescribeInstances
  - ec2:DescribeNetworkInterfaces
  - ec2:DescribeTags
  - ec2:GetCoipPoolUsage
  - ec2:DescribeCoipPools
  - elasticloadbalancing:DescribeLoadBalancers
  - elasticloadbalancing:DescribeLoadBalancerAttributes
  - elasticloadbalancing:DescribeListeners
  - elasticloadbalancing:DescribeListenerCertificates
  - elasticloadbalancing:DescribeSSLPolicies
  - elasticloadbalancing:DescribeRules
  - elasticloadbalancing:DescribeTargetGroups
  - elasticloadbalancing:DescribeTargetGroupAttributes
  - elasticloadbalancing:DescribeTargetHealth
  - elasticloadbalancing:DescribeTags
  - elasticloadbalancing:DescribeTrustStores
  - elasticloadbalancing:DescribeListenerAttributes
  Resource: "*"
- Effect: Allow
  Action:
  - cognito-idp:DescribeUserPoolClient
  - acm:ListCertificates
  - acm:DescribeCertificate
  - iam:ListServerCertificates
  - iam:GetServerCertificate
  - waf-regional:GetWebACL
  - waf-regional:GetWebACLForResource
  - waf-regional:AssociateWebACL
  - waf-regional:DisassociateWebACL
  - wafv2:GetWebACL
  - wafv2:GetWebACLForResource
  - wafv2:AssociateWebACL
  - wafv2:DisassociateWebACL
  - shield:GetSubscriptionState
  - shield:DescribeProtection
  - shield:CreateProtection
  - shield:DeleteProtection
  Resource: "*"
- Effect: Allow
  Action:
  - ec2:AuthorizeSecurityGroupIngress
  - ec2:RevokeSecurityGroupIngress
  Resource: "*"
- Effect: Allow
  Action:
  - ec2:CreateSecurityGroup
  Resource: "*"
- Effect: Allow
  Action:
  - ec2:CreateTags
  Resource: arn:{{ .Partition }}:ec2:*:*:security-group/*
  Condition:
    StringEquals:
      ec2:CreateAction: CreateSecurityGroup
    'Null':
      aws:RequestTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - ec2:CreateTags
  - ec2:DeleteTags
  Resource: arn:{{ .Partition }}:ec2:*:*:security-group/*
  Condition:
    'Null':
      aws:RequestTag/elbv2.k8s.aws/cluster: 'true'
      aws:ResourceTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - ec2:AuthorizeSecurityGroupIngress
  - ec2:RevokeSecurityGroupIngress
  - ec2:DeleteSecurityGroup
  Resource: "*"
  Condition:
    'Null':
      aws:ResourceTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - elasticloadbalancing:CreateLoadBalancer
  - elasticloadbalancing:CreateTargetGroup
  Resource: "*"
  Condition:
    'Null':
      aws:RequestTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - elasticloadbalancing:CreateListener
  - elasticloadbalancing:DeleteListener
  - elasticloadbalancing:CreateRule
  - elasticloadbalancing:DeleteRule
  Resource: "*"
- Effect: Allow
  Action:
  - elasticloadbalancing:AddTags
  - elasticloadbalancing:RemoveTags
  Resource:
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:targetgroup/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:loadbalancer/net/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:loadbalancer/app/*/*
  Condition:
    'Null':
      aws:RequestTag/elbv2.k8s.aws/cluster: 'true'
      aws:ResourceTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - elasticloadbalancing:AddTags
  - elasticloadbalancing:RemoveTags
  Resource:
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:listener/net/*/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:listener/app/*/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:listener-rule/net/*/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:listener-rule/app/*/*/*
- Effect: Allow
  Action:
  - elasticloadbalancing:ModifyLoadBalancerAttributes
  - elasticloadbalancing:SetIpAddressType
  - elasticloadbalancing:SetSecurityGroups
  - elasticloadbalancing:SetSubnets
  - elasticloadbalancing:DeleteLoadBalancer
  - elasticloadbalancing:ModifyTargetGroup
  - elasticloadbalancing:ModifyTargetGroupAttributes
  - elasticloadbalancing:DeleteTargetGroup
  - elasticloadbalancing:ModifyListenerAttributes
  Resource: "*"
  Condition:
    'Null':
      aws:ResourceTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - elasticloadbalancing:AddTags
  Resource:
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:targetgroup/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:loadbalancer/net/*/*
  - arn:{{ .Partition }}:elasticloadbalancing:*:*:loadbalancer/app/*/*
  Condition:
    StringEquals:
      elasticloadbalancing:CreateAction:
      - CreateTargetGroup
      - CreateLoadBalancer
    'Null':
      aws:RequestTag/elbv2.k8s.aws/cluster: 'false'
- Effect: Allow
  Action:
  - elasticloadbalancing:RegisterTargets
  - elasticloadbalancing:DeregisterTargets
  Resource: arn:{{ .Partition }}:elasticloadbalancing:*:*:targetgroup/*/*
- Effect: Allow
  Action:
  - elasticloadbalancing:SetWebAcl
  - elasticloadbalancing:ModifyListener
  - elasticloadbalancing:AddListenerCertificates
  - elasticloadbalancing:RemoveListenerCertificates
  - elasticloadbalancing:ModifyRule
  Resource: "*"
`

// https://github.com/aws/eks-charts/blob/master/stable/aws-load-balancer-controller/values.yaml
const valuesTemplate = `---
replicaCount: {{ .Replicas }}
image:
  tag: {{ .Version }}
fullnameOverride: aws-load-balancer-controller
clusterName: {{ .ClusterName }}
serviceAccount:
  annotations:
    {{ .IrsaAnnotation }}
  name: {{ .ServiceAccount }}
region: {{ .Region }}
vpcId: {{ .Cluster.ResourcesVpcConfig.VpcId }}
defaultTargetType: {{ .DefaultTargetType }}
{{- if .DefaultIngressClass }}
ingressClassConfig:
  default: true
{{- end }}
enableServiceMutatorWebhook: {{ not .DisableWebhook }}
`
