import boto3
from botocore.exceptions import ClientError
import time

# A script to demonstrate basic CRUD (Create, Read, Update, Delete) operations
# on an Amazon DynamoDB table using Boto3.

# --- Configuration ---
REGION = "us-east-1"
TABLE_NAME = "MyBoto3CRUDTable"
PARTITION_KEY_NAME = "Id"
PARTITION_KEY_TYPE = "S" # S for String, N for Number

dynamodb = boto3.resource('dynamodb', region_name=REGION)
dynamodb_client = boto3.client('dynamodb', region_name=REGION)

def create_table():
    """Creates a DynamoDB table."""
    print(f"--- Creating DynamoDB Table: {TABLE_NAME} ---")
    try:
        table = dynamodb.create_table(
            TableName=TABLE_NAME,
            KeySchema=[{'AttributeName': PARTITION_KEY_NAME, 'KeyType': 'HASH'}],
            AttributeDefinitions=[{'AttributeName': PARTITION_KEY_NAME, 'AttributeType': PARTITION_KEY_TYPE}],
            BillingMode='PAY_PER_REQUEST'
        )
        print("Waiting for table to become active...")
        table.wait_until_exists()
        print(f"Table {TABLE_NAME} is active.")
        return table
    except ClientError as e:
        if e.response['Error']['Code'] == 'ResourceInUseException':
            print(f"Table {TABLE_NAME} already exists. Skipping creation.")
            return dynamodb.Table(TABLE_NAME)
        else:
            raise e

def put_item(table, item_id, item_name, item_description):
    """Puts an item into the table."""
    print(f"\n--- Putting an item '{item_id}' into the table ---")
    table.put_item(
        Item={
            PARTITION_KEY_NAME: item_id,
            'Name': item_name,
            'Description': item_description
        }
    )
    print(f"Item '{item_id}' added.")

def get_item(table, item_id):
    """Gets an item from the table."""
    print(f"\n--- Getting the item '{item_id}' from the table ---")
    response = table.get_item(Key={PARTITION_KEY_NAME: item_id})
    item = response.get('Item')
    if item:
        print("Item retrieved:", item)
    else:
        print(f"Item '{item_id}' not found.")
    return item

def update_item(table, item_id, new_description):
    """Updates an item in the table."""
    print(f"\n--- Updating the item '{item_id}'s description ---")
    response = table.update_item(
        Key={PARTITION_KEY_NAME: item_id},
        UpdateExpression="SET Description = :new_desc",
        ExpressionAttributeValues={':new_desc': new_description},
        ReturnValues="UPDATED_NEW"
    )
    print("Item updated. New attributes:", response['Attributes'])

def delete_item(table, item_id):
    """Deletes an item from the table."""
    print(f"\n--- Deleting the item '{item_id}' from the table ---")
    table.delete_item(Key={PARTITION_KEY_NAME: item_id})
    print(f"Item '{item_id}' deleted.")

def delete_table(table):
    """Deletes a DynamoDB table."""
    print(f"\n--- Deleting DynamoDB Table: {TABLE_NAME} ---")
    table.delete()
    print("Waiting for table to be deleted...")
    dynamodb_client.get_waiter('table_not_exists').wait(TableName=TABLE_NAME)
    print(f"Table {TABLE_NAME} deleted successfully.")

def main():
    item_id = "item001"
    item_name = "Example Item"
    item_description = "This is a test item for CRUD operations."
    new_description = "This item has been updated by Boto3."

    try:
        table = create_table()

        put_item(table, item_id, item_name, item_description)
        get_item(table, item_id)
        update_item(table, item_id, new_description)
        
        print("\n--- Getting the updated item ---")
        get_item(table, item_id)

        delete_item(table, item_id)
        
        print("\n--- Attempting to get the deleted item (should return None) ---")
        get_item(table, item_id)

        delete_table(table)

        print("\n--- DynamoDB CRUD operations 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()
