package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	"github.com/aws/aws-cdk-go/awscdk/v2/awsec2"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
)

type InfrastructureStackProps struct {
	awscdk.StackProps
}

func NewInfrastructureStack(scope constructs.Construct, id string, props *InfrastructureStackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, &id, &props.StackProps)

	vpc := awsec2.Vpc_FromLookup(stack, jsii.String("WhatsCRM DefaultVPC"), &awsec2.VpcLookupOptions{
		IsDefault: jsii.Bool(true),
	})

	sg := awsec2.NewSecurityGroup(stack, jsii.String("WhatsCRM Instance SG"), &awsec2.SecurityGroupProps{
		Vpc:              vpc,
		Description:      jsii.String("WhatsCRM Security Group Allow SSH and HTTP"),
		AllowAllOutbound: jsii.Bool(true),
	})

	sg.AddIngressRule(awsec2.Peer_AnyIpv4(), awsec2.Port_Tcp(jsii.Number(22)), jsii.String("Allow SSH"), nil)
	sg.AddIngressRule(awsec2.Peer_AnyIpv4(), awsec2.Port_Tcp(jsii.Number(3000)), jsii.String("Allow Node.js app"), nil)
    sg.AddIngressRule(awsec2.Peer_AnyIpv4(), awsec2.Port_Tcp(jsii.Number(80)), jsii.String("Allow HTTP port 80"), nil) // <-- Agregar puerto 80

	userData := awsec2.UserData_ForLinux(nil)
	userData.AddCommands(
		jsii.String("sudo dnf update -y"),
        jsii.String(`sudo dnf groupinstall "Development Tools" -y`),
        jsii.String(`sudo dnf install nftables -y`),
//                jsii.String("sudo nft add table ip nat || true"),
//                jsii.String("sudo nft add chain ip nat PREROUTING { type nat hook prerouting priority 0 \\; } || true"),
//                jsii.String("sudo nft add rule ip nat PREROUTING tcp dport 80 redirect to 3000 || true"),

		jsii.String("sudo dnf install -y git mariadb105-server gcc-c++ make"),

		jsii.String("sudo systemctl enable --now mariadb"),
		jsii.String("sudo mysqladmin -u root password 'h3o9p7325rR!' || true"),

		jsii.String(`sudo mysql -uroot -ph3o9p7325rR\! -e "CREATE DATABASE IF NOT EXISTS whatscrm;"`),
        jsii.String(`sudo mysql -uroot -ph3o9p7325rR\! -e "SELECT User FROM mysql.user WHERE User = 'whatscrmuser' AND Host = 'localhost';" | grep -q 'whatscrmuser' || sudo mysql -uroot -ph3o9p7325rR\! -e "CREATE USER 'whatscrmuser'@'localhost' IDENTIFIED BY 'z31tg31stT\!';"`),
        jsii.String(`sudo mysql -uroot -ph3o9p7325rR\! -e "GRANT ALL PRIVILEGES ON whatscrm.* TO 'whatscrmuser'@'localhost';"`),
        jsii.String(`sudo mysql -uroot -ph3o9p7325rR\! -e "FLUSH PRIVILEGES;"`),
		jsii.String(`sudo -u ec2-user git config --global user.name "ccasanovas"`),
		jsii.String(`sudo -u ec2-user git config --global user.email "ccasanovas.comex@gmail.com.com"`),

        jsii.String(`sudo -u ec2-user bash -c 'if [ ! -d /home/ec2-user/meta-crm ]; then git clone https://ccasanovas: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@github.com/ccasanovas/meta-crm.git /home/ec2-user/meta-crm; else cd /home/ec2-user/meta-crm && git pull; fi'`),
		jsii.String(`if [ -f /home/ec2-user/meta-crm/export.sql ]; then sudo -u ec2-user mysql -u whatscrmuser -pz31tg31stT\! whatscrm < /home/ec2-user/meta-crm/export.sql; fi`),

        jsii.String(`TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")`),
        jsii.String(`PUBLIC_DNS=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname)`),

		jsii.String(`sudo -u ec2-user sed -i 's/^DB_USER=.*/DB_USER=whatscrmuser/' /home/ec2-user/meta-crm/.env`),
		jsii.String(`sudo -u ec2-user sed -i 's/^DB_PASSWORD=.*/DB_PASSWORD=z31tg31stT!/' /home/ec2-user/meta-crm/.env`),
		jsii.String(`sudo -u ec2-user sed -i 's/^DB_NAME=.*/DB_NAME=whatscrm/' /home/ec2-user/meta-crm/.env`),
        jsii.String(`sudo -u ec2-user sed -i "s|^FRONTENDURI=.*|FRONTENDURI=http://$PUBLIC_DNS|" /home/ec2-user/meta-crm/.env || echo "FRONTENDURI=http://$PUBLIC_DNS" | sudo -u ec2-user tee -a /home/ec2-user/meta-crm/.env`),
        jsii.String(`sudo -u ec2-user sed -i "s|^BACKENDURI=.*|BACKENDURI=http://$PUBLIC_DNS:3000|" /home/ec2-user/meta-crm/.env || echo "BACKENDURI=http://$PUBLIC_DNS:3000" | sudo -u ec2-user tee -a /home/ec2-user/meta-crm/.env`),

        jsii.String(`sudo -u ec2-user bash -l -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash && source /home/ec2-user/.nvm/nvm.sh && nvm install 21 && nvm alias default 21 && nvm use 21.7.3""`),
        jsii.String(`sudo -u ec2-user bash -l -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash"`),
        jsii.String(`sudo -u ec2-user bash -l -c "source /home/ec2-user/.nvm/nvm.sh"`),
        jsii.String(`sudo -u ec2-user bash -l -c "nvm install 21"`),
        jsii.String(`sudo -u ec2-user bash -l -c "nvm alias default 21"`),
        jsii.String(`sudo -u ec2-user bash -l -c "nvm use 21.7.3"`),
        jsii.String(`cd /home/ec2-user/meta-crm`),
        jsii.String(`sudo fallocate -l 2G /swapfile`),
        jsii.String(`sudo chmod 600 /swapfile`),
        jsii.String(`sudo mkswap /swapfile`),
        jsii.String(`sudo swapon /swapfile`),
        jsii.String(`npm install -g yarn`),
        jsii.String(`yarn install --ignore-engines`),
    jsii.String(`sudo tee /etc/systemd/system/meta-crm.service > /dev/null <<EOF
[Unit]
Description=Meta CRM Initialization Script
After=network.target mariadb.service

[Service]
Type=simple
User=ec2-user
ExecStart=/home/ec2-user/init-meta-crm.sh
Restart=no

[Install]
WantedBy=multi-user.target
EOF`),

    jsii.String(`nohup node /home/ec2-user/meta-crm/server.js > /home/ec2-user/app.log 2>&1 &`),
    //jsii.String(`sudo systemctl enable meta-crm.service`),
    //jsii.String(`sudo systemctl start meta-crm.service`),
            //jsii.String(`[ -n "$PUBLIC_DNS" ] && sudo -u ec2-user sed -i "s|process.env.FRONTENDURI|\"$PUBLIC_DNS\"|g" /home/ec2-user/meta-crm/client/static/js/*.js || true`),
        //jsii.String(`nohup node /home/ec2-user/meta-crm/server.js > /home/ec2-user/app.log 2>&1 &`),
    )

	key := awsec2.NewCfnKeyPair(stack, jsii.String("WhatsCRMKeyPair"), &awsec2.CfnKeyPairProps{
		KeyName: jsii.String("whatscrm-key"),
	})

	instance := awsec2.NewInstance(stack, jsii.String("WhatsCRMInstance"), &awsec2.InstanceProps{
		InstanceType:  awsec2.InstanceType_Of(awsec2.InstanceClass_T3, awsec2.InstanceSize_MICRO),
		MachineImage:  awsec2.MachineImage_LatestAmazonLinux2023(&awsec2.AmazonLinux2023ImageSsmParameterProps{}),
		Vpc:           vpc,
		SecurityGroup: sg,
		KeyName:       key.KeyName(),
		UserData:      userData,
	})

    doc := awsssm.NewCfnDocument(stack, jsii.String("MetaCRMRestartDoc"), &awsssm.CfnDocumentProps{
        Content: map[string]interface{}{
            "schemaVersion": "2.0",
            "description":   "Restart meta-crm.service",
            "mainSteps": []map[string]interface{}{
                {
                    "action": "aws:runShellScript",
                    "name":   "restartMetaCRMService",
                    "inputs": map[string]interface{}{
                        "runCommand": []string{
                            "sudo systemctl daemon-reload",
                            "sudo systemctl enable meta-crm.service",
                            "sudo systemctl restart meta-crm.service || sudo systemctl start meta-crm.service",
                        },
                    },
                },
            },
        },
        DocumentType: jsii.String("Command"),
    })

    awsssm.NewCfnAssociation(stack, jsii.String("MetaCRMRestartAssociation"), &awsssm.CfnAssociationProps{
        Name:       doc.Ref(),
        InstanceId: instance.InstanceId(),
    })
	awscdk.NewCfnOutput(stack, jsii.String("WhatsCRMInstancePublicIP"), &awscdk.CfnOutputProps{
		Value:       instance.InstancePublicIp(),
		Description: jsii.String("WhatsCRM Instance Public IP of EC2 instance"),
	})

	return stack
}

func main() {
	app := awscdk.NewApp(nil)

	NewInfrastructureStack(app, "WhatsCRMStack", &InfrastructureStackProps{
		awscdk.StackProps{
			Env: env(),
		},
	})

	app.Synth(nil)
}

func env() *awscdk.Environment {
	return &awscdk.Environment{
		Region:  jsii.String("sa-east-1"),
		Account: jsii.String("899848371761"),
	}
}
