from typing import Dict, Union
import os

from fastapi import FastAPI, Body
from pydantic import BaseModel
from peewee import (
    Model, IntegerField, TextField, CompositeKey, IntegrityError
)
from playhouse.postgres_ext import JSONField
from playhouse.pool import PooledPostgresqlExtDatabase

DB = PooledPostgresqlExtDatabase(
    database=os.environ['DATABASE'],
    user=os.environ['USER'],
    password=os.environ['PASSWORD'],
    host=os.environ['HOST'],
    max_connections=19,
    stale_timeout=10,
)


class Submission_api(BaseModel):
    learning_unit: Union[str, int]
    slack_id: str = Body(..., min_length=5, max_length=20)
    grade: int
    metadata: Dict[str, str]


class Submission_db(Model):
    learning_unit = IntegerField()
    slack_id = TextField()
    grade = IntegerField()
    metadata = JSONField()

    class Meta:
        database = DB
        primary_key = CompositeKey('learning_unit', 'slack_id')


DB.create_tables([Submission_db], safe=True)

app = FastAPI()


# This hook ensures that a connection is opened to handle any queries
# generated by the request .
@app.on_event("startup")
def startup():
    DB.connect(reuse_if_open=True)


# This hook ensures that the connection is closed when we've finished
# processing the request.
@app.on_event("shutdown")
def shutdown():
    if not DB.is_closed():
        DB.close()


@app.put("/submit")
def submit(
    submission_api: Submission_api
):
    submission_db = Submission_db(
        learning_unit=str(submission_api.learning_unit),
        slack_id=submission_api.slack_id,
        grade=submission_api.grade,
        metadata=submission_api.metadata
    )
    try:
        submission_db.save(force_insert=True)
    except IntegrityError:
        # no ned to do anyhting, means the student has already submited
        DB.rollback()

    return 'OK'
