import os
from datetime import timedelta

import pytz
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.data_classes import (
    EventBridgeEvent,
    event_source,
)
from aws_lambda_powertools.utilities.typing import LambdaContext
from layercake.dateutils import fromisoformat, now, ttl
from layercake.dynamodb import DynamoDBPersistenceLayer
from layercake.funcs import pick

from boto3clients import dynamodb_client
from config import ENROLLMENT_TABLE

logger = Logger(__name__)
dyn = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
tz = os.getenv('TZ', 'UTC')


@event_source(data_class=EventBridgeEvent)
@logger.inject_lambda_context
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool | None:
    new_image = event.detail['new_image']
    enrollment_id = new_image['id']
    org_id = new_image['org_id']
    expires_at = fromisoformat(new_image['cert_expires_at']).replace(  # type: ignore
        tzinfo=pytz.timezone(tz)
    )

    target_month = expires_at.strftime('%Y-%m')
    now_ = now(tz)
    pk = f'CERT_REPORTING#ORG#{org_id}'

    try:
        if now_ > expires_at:
            raise InvalidDateError('Invalid date')

        # The reporting month is the month before the certificate expires
        report_month = (expires_at.replace(day=1) - timedelta(days=1)).replace(day=1)
        report_sk = report_month.strftime('%Y-%m')

        with dyn.transact_writer() as transact:
            transact.put(
                item={
                    'id': pk,
                    'sk': f'MONTH#{report_sk}',
                    'status': 'PENDING',
                    'target_month': target_month,
                    'created_at': now_,
                },
                cond_expr='attribute_not_exists(sk)',
                exc_cls=ReportExistsError,
            )
            transact.put(
                item={
                    'id': pk,
                    'sk': f'MONTH#{report_sk}#SCHEDULE#SEND_REPORT_EMAIL',
                    'target_month': target_month,
                    'ttl': ttl(start_dt=report_month),
                    'created_at': now_,
                },
            )
    except Exception as exc:
        logger.info(exc)

    try:
        dyn.put_item(
            item={
                'id': pk,
                'sk': f'MONTH#{target_month}#ENROLLMENT#{enrollment_id}',
                'user': pick(('id', 'name'), new_image['user']),
                'course': pick(('id', 'name'), new_image['course']),
                'enrolled_at': new_image['created_at'],
                'expires_at': expires_at,
                'completed_at': new_image['completed_at'],
                'created_at': now_,
            },
            cond_expr='attribute_not_exists(sk)',
        )
    except Exception:
        return False
    else:
        return True


class InvalidDateError(Exception): ...


class ReportExistsError(Exception):
    def __init__(self, *args: object) -> None:
        super().__init__('Report already exists')
