import uuid
from datetime import datetime
from http import HTTPStatus

from aws_lambda_powertools.event_handler.api_gateway import Router
from layercake.batch import BatchProcessor
from layercake.dynamodb import (
    DynamoDBCollection,
    DynamoDBPersistenceLayer,
)
from pydantic import BaseModel

from api_gateway import JSONResponse
from boto3clients import dynamodb_client
from config import (
    ENROLLMENT_TABLE,
    USER_TABLE,
)
from middlewares import Tenant, TenantMiddleware
from models import Course, Enrollment, User
from rules.enrollment import DeduplicationWindow, Slot, enroll

router = Router()

enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
user_layer = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
user_collect = DynamoDBCollection(user_layer)
enrollment_collect = DynamoDBCollection(enrollment_layer)
processor = BatchProcessor()


class Item(BaseModel):
    user: User
    course: Course
    slot: Slot | None = None
    deduplication_window: DeduplicationWindow | None = None
    schedule_date: datetime | None = None

    @property
    def id(self) -> str:
        if not self.slot:
            return str(uuid.uuid4())

        _, idx = self.slot.sk.split('#')
        return idx


class Payload(BaseModel):
    items: tuple[Item, ...]


@router.post(
    '/',
    compress=True,
    tags=['Enrollment'],
    middlewares=[
        TenantMiddleware(user_collect),
    ],
)
def enroll_(payload: Payload):
    context = {'tenant': router.context['tenant']}

    with processor(payload.items, handler, context):
        processed_messages = processor.process()

    return JSONResponse(HTTPStatus.OK, processed_messages)


def handler(record: Item, context: dict):
    tenant: Tenant = context['tenant']
    enrollment = Enrollment(
        id=record.id,
        user=record.user,
        course=record.course,
    )

    enroll(
        enrollment=enrollment,
        tenant={
            'id': str(tenant.id),
            'name': tenant.name,
        },
        deduplication_window=record.deduplication_window,
        slot=record.slot,
        persistence_layer=enrollment_layer,
    )

    return enrollment
