import boto3
from botocore.exceptions import ClientError
import time
from datetime import datetime, timedelta

# A script to demonstrate creating a custom CloudWatch metric, publishing data to it,
# and setting up an alarm using Boto3.

# --- Configuration ---
REGION = "us-east-1"
NAMESPACE = "MyBoto3Application"
METRIC_NAME = "CustomTransactionCount"
ALARM_NAME = "HighCustomTransactionCountAlarmBoto3"
THRESHOLD = 5
PERIOD = 60 # seconds
EVALUATION_PERIODS = 1

cloudwatch_client = boto3.client('cloudwatch', region_name=REGION)

def publish_metric_data():
    """Publishes custom metric data to CloudWatch."""
    print(f"--- Publishing custom metric data to {NAMESPACE}/{METRIC_NAME} ---")

    # Publish a few data points below the threshold
    print("Publishing data points (below threshold)...")
    cloudwatch_client.put_metric_data(
        Namespace=NAMESPACE,
        MetricData=[
            {
                'MetricName': METRIC_NAME,
                'Dimensions': [{'Name': 'Service', 'Value': 'Auth'}, {'Name': 'Region', 'Value': REGION}],
                'Timestamp': datetime.utcnow() - timedelta(minutes=2),
                'Value': 2,
                'Unit': 'Count'
            },
            {
                'MetricName': METRIC_NAME,
                'Dimensions': [{'Name': 'Service', 'Value': 'Auth'}, {'Name': 'Region', 'Value': REGION}],
                'Timestamp': datetime.utcnow() - timedelta(minutes=1),
                'Value': 3,
                'Unit': 'Count'
            }
        ]
    )
    time.sleep(5)

    # Publish a data point above the threshold to trigger the alarm
    print("Publishing data point (above threshold) to trigger alarm...")
    cloudwatch_client.put_metric_data(
        Namespace=NAMESPACE,
        MetricData=[
            {
                'MetricName': METRIC_NAME,
                'Dimensions': [{'Name': 'Service', 'Value': 'Auth'}, {'Name': 'Region', 'Value': REGION}],
                'Timestamp': datetime.utcnow(),
                'Value': 6,
                'Unit': 'Count'
            }
        ]
    )
    print("Metric data published.")

def create_cloudwatch_alarm():
    """Creates a CloudWatch alarm."""
    print(f"\n--- Creating CloudWatch Alarm: {ALARM_NAME} ---")
    try:
        # Note: For a real-world scenario, you would typically configure an SNS topic
        # for alarm actions. For this demo, we'll create an alarm without an action
        # to keep it simple, but it will still change state.
        cloudwatch_client.put_metric_alarm(
            AlarmName=ALARM_NAME,
            AlarmDescription="Alarm when custom transaction count is too high",
            MetricName=METRIC_NAME,
            Namespace=NAMESPACE,
            Statistic='Sum',
            Period=PERIOD,
            Threshold=THRESHOLD,
            ComparisonOperator='GreaterThanThreshold',
            EvaluationPeriods=EVALUATION_PERIODS,
            Dimensions=[{'Name': 'Service', 'Value': 'Auth'}, {'Name': 'Region', 'Value': REGION}]
        )
        print(f"Alarm '{ALARM_NAME}' created.")
        print(f"The alarm will transition to ALARM state if the metric value stays above {THRESHOLD} for {EVALUATION_PERIODS} period(s) of {PERIOD} seconds.")
        print("You can check the alarm state in the CloudWatch console.")
    except ClientError as e:
        print(f"Error creating alarm: {e}")
        raise

def delete_cloudwatch_alarm():
    """Deletes the CloudWatch alarm."""
    print(f"\n--- Deleting CloudWatch Alarm: {ALARM_NAME} ---")
    try:
        cloudwatch_client.delete_alarms(AlarmNames=[ALARM_NAME])
        print(f"Alarm '{ALARM_NAME}' deleted.")
    except ClientError as e:
        if e.response['Error']['Code'] == 'ResourceNotFound':
            print(f"Alarm '{ALARM_NAME}' not found, skipping deletion.")
        else:
            print(f"Error deleting alarm: {e}")
            raise

def main():
    try:
        publish_metric_data()
        create_cloudwatch_alarm()
        
        input("Press Enter to clean up resources (delete alarm)...")
        delete_cloudwatch_alarm()
        
        print("\n--- CloudWatch custom metric and alarm demonstration complete ---")

    except ClientError as e:
        print(f"An AWS client error occurred: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

if __name__ == "__main__":
    main()
