from __future__ import annotations

import json
import os
from dataclasses import dataclass
from typing import Dict, Any

import boto3


@dataclass
class DeployInputs:
    region: str
    bucket_processed: str
    resource_tag: str
    budget_cap_usd: float
    email_for_alerts: str | None
    enable_ec2: bool


def estimate_monthly_cost(invocations: int = 10000, s3_gb: float = 1.0, ec2_hours: int = 0) -> float:
    # naive estimate; documented in README
    lambda_cost = max(invocations / 1000000 * 0.20, 0.0)
    s3_cost = s3_gb * 0.023
    ec2_cost = ec2_hours * 0.0104  # t3.micro us-east-1 on-demand approx per hour
    return round(lambda_cost + s3_cost + ec2_cost, 2)


def create_resources(i: DeployInputs) -> Dict[str, Any]:
    session = boto3.session.Session(region_name=i.region)
    s3 = session.client("s3")
    budgets = session.client("budgets")
    sns = session.client("sns")

    # Create processed bucket
    try:
        s3.head_bucket(Bucket=i.bucket_processed)
    except Exception:
        kwargs = {"Bucket": i.bucket_processed}
        if i.region != "us-east-1":
            kwargs["CreateBucketConfiguration"] = {"LocationConstraint": i.region}
        s3.create_bucket(**kwargs)
        s3.put_bucket_tagging(Bucket=i.bucket_processed, Tagging={"TagSet": [{"Key": "resource-tag", "Value": i.resource_tag}]})

    # SNS topic for alerts (optional)
    topic_arn = None
    if i.email_for_alerts:
        topic = sns.create_topic(Name=f"ransom-analysis-{i.resource_tag}")
        topic_arn = topic["TopicArn"]
        sns.set_topic_attributes(TopicArn=topic_arn, AttributeName="DisplayName", AttributeValue="RansomAnalysisBudget")
        sns.subscribe(TopicArn=topic_arn, Protocol="email", Endpoint=i.email_for_alerts)

    # Budget
    try:
        budgets.create_budget(
            AccountId=boto3.client("sts").get_caller_identity()["Account"],
            Budget={
                "BudgetName": f"ransom-budget-{i.resource_tag}",
                "BudgetLimit": {"Amount": str(i.budget_cap_usd), "Unit": "USD"},
                "CostFilters": {},
                "CostTypes": {"IncludeCredit": True, "IncludeDiscount": True, "IncludeOtherSubscription": True, "IncludeRecurring": True, "IncludeRefund": True, "IncludeSubscription": True, "IncludeSupport": True, "IncludeTax": True, "IncludeUpfront": True, "UseAmortized": False, "UseBlended": False},
                "TimeUnit": "MONTHLY",
                "BudgetType": "COST",
            },
            NotificationsWithSubscribers=[
                {
                    "Notification": {"NotificationType": "ACTUAL", "ComparisonOperator": "GREATER_THAN", "Threshold": 80.0, "ThresholdType": "PERCENTAGE"},
                    "Subscribers": ([{"SubscriptionType": "SNS", "Address": topic_arn}] if topic_arn else []),
                }
            ],
        )
    except Exception:
        # Instruct user via logs in workflow if budget API blocked
        pass

    return {"bucket": i.bucket_processed, "sns_topic": topic_arn}


def main():
    region = os.getenv("AWS_REGION", "us-east-1")
    inputs = DeployInputs(
        region=region,
        bucket_processed=os.getenv("S3_BUCKET_PROCESSED", "ransom-analysis-processed"),
        resource_tag=os.getenv("RESOURCE_TAG", "ransom-analysis:local"),
        budget_cap_usd=float(os.getenv("BUDGET_CAP_USD", "5.0")),
        email_for_alerts=os.getenv("EMAIL_FOR_ALERTS"),
        enable_ec2=os.getenv("ENABLE_EC2", "false").lower() == "true",
    )
    est = estimate_monthly_cost()
    print(json.dumps({"estimated_monthly_cost_usd": est}, indent=2))
    if os.getenv("CONFIRM_DEPLOY", "false").lower() != "true":
        print("Dry run only. Set CONFIRM_DEPLOY=true to create resources.")
        return
    out = create_resources(inputs)
    print(json.dumps(out))


if __name__ == "__main__":
    main()


