from datetime import datetime
from http import HTTPStatus
from io import BytesIO
from typing import Annotated, Any
from urllib.parse import urlparse

import requests
from aws_lambda_powertools.event_handler.api_gateway import Response, Router
from aws_lambda_powertools.event_handler.exceptions import (
    BadRequestError,
    NotFoundError,
)
from aws_lambda_powertools.event_handler.openapi.params import Body
from layercake.dateutils import now
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
from pydantic import UUID4, BaseModel

from api_gateway import JSONResponse
from boto3clients import dynamodb_client, s3_client
from config import BUCKET_NAME, COURSE_TABLE, PAPERFORGE_API
from form_data import parse

router = Router()
dyn = DynamoDBPersistenceLayer(COURSE_TABLE, dynamodb_client)


@router.get('/<course_id>')
def get_course(course_id: str):
    return dyn.collection.get_item(
        KeyPair(course_id, '0'),
        exc_cls=NotFoundError,
    )


@router.post('/<course_id>/scormset/<scormset_id>')
def get_scormset(course_id: str, scormset_id: str):
    return dyn.collection.get_item(
        KeyPair(course_id, f'SCORMSET#{scormset_id}'),
        exc_cls=NotFoundError,
    )


class Cert(BaseModel):
    exp_interval: int | None = None
    s3_uri: str | None = None

    def model_dump(self, **kwargs) -> dict[str, Any]:
        return super().model_dump(exclude_none=True, **kwargs)


class Course(BaseModel):
    id: UUID4
    name: str
    access_period: int
    cert: Cert
    unlisted: bool = False
    rawfile: bytes | None = None


@router.put('/<course_id>')
def put_course(course_id: str):
    event = router.current_event

    if not event.decoded_body:
        raise BadRequestError('Invalid request body')

    body = parse(
        event.headers,
        BytesIO(event.decoded_body.encode()),
    )
    course = Course.model_validate({'id': course_id, 'cert': {}} | body)

    if course.rawfile:
        object_key = f'certs/templates/{course_id}.html'
        course.cert.s3_uri = f's3://{BUCKET_NAME}/{object_key}'

        s3_client.put_object(
            Bucket=BUCKET_NAME,
            Key=object_key,
            Body=course.rawfile,
            ContentType='text/html',
        )

    with dyn.transact_writer() as transact:
        transact.update(
            key=KeyPair(str(course.id), '0'),
            update_expr='SET #name = :name, \
                             access_period = :access_period, \
                             cert = :cert, \
                             unlisted = :unlisted, \
                             updated_at = :updated_at',
            expr_attr_names={
                '#name': 'name',
            },
            expr_attr_values={
                ':name': course.name,
                ':cert': course.cert.model_dump(),
                ':access_period': course.access_period,
                ':unlisted': course.unlisted,
                ':updated_at': now(),
            },
            cond_expr='attribute_exists(sk)',
            exc_cls=BadRequestError,
        )

    return JSONResponse(HTTPStatus.NO_CONTENT)


@router.post('/<course_id>/sample')
def sample(course_id: str, s3_uri: Annotated[str, Body(embed=True)]):
    now_ = now()
    # Send template URI and data to Paperforge API to generate a PDF
    r = requests.post(
        PAPERFORGE_API,
        json={
            'template_uri': s3_uri,
            'args': {
                'name': 'Juscelino Kubitschek',
                'cpf': '***.810.132-**',
                'score': 100,
                'started_at': now_.strftime('%d/%m/%Y'),
                'completed_at': now_.strftime('%d/%m/%Y'),
                'today': _datefmt(now_),
                'year': now_.strftime('%Y'),
                'expires_at': now_.strftime('%d/%m/%Y'),
            },
        },
    )
    r.raise_for_status()

    return Response(
        body=r.content,
        content_type='application/pdf',
        status_code=HTTPStatus.OK,
        headers={
            'Content-Disposition': f'attachment; filename="{course_id}.pdf"',
        },
    )


@router.post('/<course_id>/template')
def template(course_id: str, s3_uri: Annotated[str, Body(embed=True)]):
    parsed = urlparse(s3_uri)

    bucket = parsed.netloc
    object_key = parsed.path.lstrip('/')

    r = s3_client.get_object(Bucket=bucket, Key=object_key)

    return Response(
        body=r['Body'].read(),
        content_type='text/html',
        status_code=HTTPStatus.OK,
        headers={
            'Content-Disposition': f'attachment; filename="{course_id}.html"',
        },
    )


def _datefmt(dt: datetime) -> str:
    months = [
        'Janeiro',
        'Fevereiro',
        'Março',
        'Abril',
        'Maio',
        'Junho',
        'Julho',
        'Agosto',
        'Setembro',
        'Outubro',
        'Novembro',
        'Dezembro',
    ]
    return f'{dt.day:02d} de {months[dt.month - 1]} de {dt.year}'
