#!/usr/bin/env bash
set -euo pipefail

TARGET_ROOT="${1:-.}"
BLACKSHIELD_API_URL="${BLACKSHIELD_API_URL:-https://api.blackshield.chaplau.com}"
BLACKSHIELD_VMS_IMAGE="${BLACKSHIELD_VMS_IMAGE:-public.ecr.aws/blackshield-security/vms-scanner:1.0.6}"

mkdir -p "$TARGET_ROOT/deploy/aws-vm-scanner"

cat > "$TARGET_ROOT/deploy/aws-vm-scanner/app.py" <<'EOF'
#!/usr/bin/env python3
"""CDK entry point for the BlackShield VM scanner on AWS."""

import os
import sys

# --- Preflight Guard ---
if sys.version_info < (3, 11):
    print(f"Error: Python 3.11+ is required (current: {sys.version_info.major}.{sys.version_info.minor})")
    print("Recovery: python3.11 -m venv .venv && source .venv/bin/activate && python -m pip install -r requirements.txt")
    sys.exit(1)


def get_required_env(name: str) -> str:
    """Retrieve environment variable or fail with actionable message."""
    val = os.environ.get(name)
    if not val:
        print(f"Error: Environment variable {name} is required for deployment.")
        print(f"Fix: export {name}=...")
        sys.exit(1)
    return val


import aws_cdk as cdk

from vm_scanner_stack import VmScannerStack

app = cdk.App()

env = cdk.Environment(
    account=os.environ.get("CDK_DEFAULT_ACCOUNT"),
    region=os.environ.get("CDK_DEFAULT_REGION", "us-east-1"),
)

VmScannerStack(
    app,
    app.node.try_get_context("stack_name") or "BlackShieldVmScanner",
    env=env,
    blackshield_api_url=(
        app.node.try_get_context("api_url") or get_required_env("BLACKSHIELD_API_URL")
    ),
    secret_name=(
        app.node.try_get_context("secret_name")
        or os.environ.get("SECRET_NAME", "blackshield/vm-scanner/api-key")
    ),
    scanner_image_uri=(
        app.node.try_get_context("image_uri") or get_required_env("SCANNER_IMAGE_URI")
    ),
    alerts_object_key=(
        app.node.try_get_context("alerts_object_key")
        or os.environ.get("ALERTS_OBJECT_KEY", "prod/default/alerts.json")
    ),
    scan_interval_seconds=int(
        app.node.try_get_context("scan_interval_seconds")
        or os.environ.get("SCAN_INTERVAL_SECONDS", "60")
    ),
    vpc_id=app.node.try_get_context("vpc_id") or os.environ.get("VPC_ID"),
)

cdk.Tags.of(app).add("Project", "SecurityPlatform")
cdk.Tags.of(app).add("ManagedBy", "CDK")
cdk.Tags.of(app).add("Component", "vm-scanner")

app.synth()
EOF

cat > "$TARGET_ROOT/deploy/aws-vm-scanner/cdk.json" <<'EOF'
{
  "app": "python app.py",
  "context": {
    "@aws-cdk/core:checkSecretUsage": true,
    "@aws-cdk/aws-iam:minimizePolicies": true
  }
}
EOF

cat > "$TARGET_ROOT/deploy/aws-vm-scanner/requirements.txt" <<'EOF'
aws-cdk-lib>=2.130.0
constructs>=10.0.0
EOF

cat > "$TARGET_ROOT/deploy/aws-vm-scanner/vm_scanner_stack.py" <<'EOF'
"""CDK stack for the BlackShield VM scanner on AWS."""

from aws_cdk import (
    CfnOutput,
    RemovalPolicy,
    Stack,
    aws_ec2 as ec2,
    aws_ecs as ecs,
    aws_iam as iam,
    aws_logs as logs,
    aws_s3 as s3,
    aws_secretsmanager as secretsmanager,
)
from constructs import Construct


class VmScannerStack(Stack):
    """Deploy the VM scanner as a long-running ECS Fargate service."""

    def __init__(
        self,
        scope: Construct,
        construct_id: str,
        blackshield_api_url: str,
        secret_name: str,
        scanner_image_uri: str,
        alerts_object_key: str,
        scan_interval_seconds: int,
        vpc_id: str | None = None,
        **kwargs: object,
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        if vpc_id:
            vpc = ec2.Vpc.from_lookup(self, "ScannerVpc", vpc_id=vpc_id)
        else:
            vpc = ec2.Vpc(
                self,
                "ScannerVpc",
                max_azs=2,
                nat_gateways=0,
                subnet_configuration=[
                    ec2.SubnetConfiguration(
                        name="Public",
                        subnet_type=ec2.SubnetType.PUBLIC,
                        cidr_mask=24,
                    )
                ],
            )

        bucket = s3.Bucket(
            self,
            "AlertsBucket",
            versioned=True,
            encryption=s3.BucketEncryption.S3_MANAGED,
            enforce_ssl=True,
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
            removal_policy=RemovalPolicy.DESTROY,
            auto_delete_objects=True,
        )

        cluster = ecs.Cluster(
            self,
            "ScannerCluster",
            cluster_name=f"{construct_id}-cluster",
            vpc=vpc,
        )

        task_role = iam.Role(
            self,
            "ScannerTaskRole",
            assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
            description="Read-only role for BlackShield VM scanner service",
        )
        bucket.grant_read(task_role)

        secret = secretsmanager.Secret.from_secret_name_v2(
            self,
            "ApiKeySecret",
            secret_name,
        )

        log_group = logs.LogGroup(
            self,
            "ScannerLogs",
            log_group_name=f"/aws/ecs/{construct_id}",
            retention=logs.RetentionDays.ONE_MONTH,
            removal_policy=RemovalPolicy.DESTROY,
        )

        task_definition = ecs.FargateTaskDefinition(
            self,
            "ScannerTaskDefinition",
            family=f"{construct_id}-task",
            cpu=1024,
            memory_limit_mib=2048,
            task_role=task_role,
        )

        task_definition.add_container(
            "VmScannerContainer",
            image=ecs.ContainerImage.from_registry(scanner_image_uri),
            logging=ecs.LogDrivers.aws_logs(
                stream_prefix="vm-scanner",
                log_group=log_group,
            ),
            environment={
                "BLACKSHIELD_API_URL": blackshield_api_url,
                "VMS_COLLECTOR_MODE": "s3",
                "VMS_SOURCE_URI": f"s3://{bucket.bucket_name}/{alerts_object_key}",
                "OSSEC_STATE_FILE": "/tmp/vms-state/ossec-state.json",
                "SCAN_INTERVAL_SECONDS": str(scan_interval_seconds),
                "SCAN_ON_STARTUP": "true",
                "MIN_SEVERITY": "high",
                "LOG_LEVEL": "INFO",
            },
            secrets={
                "BLACKSHIELD_API_KEY": ecs.Secret.from_secrets_manager(secret),
            },
        )

        security_group = ec2.SecurityGroup(
            self,
            "ScannerSecurityGroup",
            vpc=vpc,
            allow_all_outbound=True,
            description="Outbound-only SG for BlackShield VM scanner",
        )

        service = ecs.FargateService(
            self,
            "VmScannerService",
            cluster=cluster,
            task_definition=task_definition,
            desired_count=1,
            assign_public_ip=True,
            security_groups=[security_group],
            vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC),
        )

        CfnOutput(self, "AlertsBucketName", value=bucket.bucket_name)
        CfnOutput(
            self,
            "AlertsObjectUri",
            value=f"s3://{bucket.bucket_name}/{alerts_object_key}",
        )
        CfnOutput(self, "ClusterName", value=cluster.cluster_name)
        CfnOutput(self, "ServiceName", value=service.service_name)
        CfnOutput(self, "LogGroupName", value=log_group.log_group_name)
EOF

cat > "$TARGET_ROOT/deploy/aws-vm-scanner/host-sync-to-s3.sh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

SOURCE_FILE="${1:-/var/ossec/logs/alerts/alerts.json}"
S3_URI="${2:-s3://replace-me/prod/default/alerts.json}"
SYNC_INTERVAL_SECONDS="${SYNC_INTERVAL_SECONDS:-30}"

if ! command -v aws >/dev/null 2>&1; then
  echo "aws CLI is required for host-sync-to-s3.sh" >&2
  exit 1
fi

while true; do
  if [ -f "$SOURCE_FILE" ]; then
    aws s3 cp "$SOURCE_FILE" "$S3_URI" --only-show-errors
  else
    echo "alerts file not found yet: $SOURCE_FILE" >&2
  fi
  sleep "$SYNC_INTERVAL_SECONDS"
done
EOF
chmod +x "$TARGET_ROOT/deploy/aws-vm-scanner/host-sync-to-s3.sh"

cat > "$TARGET_ROOT/deploy/aws-vm-scanner/README.md" <<EOF
# AWS VM Scanner Bundle

1. Create a Python 3.11 virtual environment and install dependencies:

\`\`\`bash
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
\`\`\`

2. Create the API key secret once per account:

\`\`\`bash
aws secretsmanager create-secret \\
  --name blackshield/vm-scanner/api-key \\
  --secret-string '{"BLACKSHIELD_API_KEY":"sp_xxxx"}'
\`\`\`

3. Deploy the ECS Fargate service and supporting S3 bucket:

\`\`\`bash
export BLACKSHIELD_API_URL=${BLACKSHIELD_API_URL}
export SCANNER_IMAGE_URI=${BLACKSHIELD_VMS_IMAGE}
cdk bootstrap
cdk deploy --require-approval never
\`\`\`

4. Start the host-side upload helper from the OSSEC or Wazuh host once the stack
outputs the bucket and object URI:

\`\`\`bash
./host-sync-to-s3.sh /var/ossec/logs/alerts/alerts.json s3://<bucket>/<object-key>
\`\`\`

The ECS service runs continuously with \`VMS_COLLECTOR_MODE=s3\` and tails the
uploaded object incrementally using object version plus byte-offset state.
EOF

printf 'Wrote deploy/aws-vm-scanner/app.py\n'
printf 'Wrote deploy/aws-vm-scanner/cdk.json\n'
printf 'Wrote deploy/aws-vm-scanner/requirements.txt\n'
printf 'Wrote deploy/aws-vm-scanner/vm_scanner_stack.py\n'
printf 'Wrote deploy/aws-vm-scanner/host-sync-to-s3.sh\n'
printf 'Wrote deploy/aws-vm-scanner/README.md\n'
