import uuid
from fastapi import Depends, HTTPException, File, UploadFile
import shutil

from ..core.routes import get_crud_router
from .routes_draft import draft_router
from .print import print_router

from .models import Contract, ContractDraft, ContractDraftStatus, Party, replace_variables_in_value
from .schemas import ContractCreate, ContractRead, ContractUpdate, SignatureRead

from ..entity.models import Entity
from ..template.models import ProvisionTemplate
from ..user.manager import get_current_user, get_current_superuser

contract_router = get_crud_router(Contract, ContractCreate, ContractRead, ContractUpdate)
del(contract_router.routes[0])
del(contract_router.routes[2])
del(contract_router.routes[2])

contract_router.include_router(draft_router, prefix="/draft", )
contract_router.include_router(print_router, prefix="/print", )


@contract_router.post("/", response_description="Contract Successfully created")
async def create(item: ContractCreate, user=Depends(get_current_user)) -> dict:
    await item.validate_foreign_key()

    draft = await ContractDraft.get(item.draft_id)

    for v in draft.variables:
        if not v.key or not v.value:
            raise HTTPException(status_code=400, detail="Variable {} is invalid".format(v))

    contract_dict = item.dict()
    del(contract_dict['draft_id'])

    contract_dict['lawyer'] = await Entity.get(user.entity_id)

    contract_dict['name'] = draft.name
    contract_dict['title'] = draft.title
    parties = []
    for p in draft.parties:
        parties.append({
            'entity': await Entity.get(p.entity_id),
            'part': p.part,
            'representative': await Entity.get(p.representative_id) if p.representative_id else None,
            'signature_uuid': str(uuid.uuid4())
        })

    contract_dict['parties'] = parties

    provisions = []
    for p in draft.provisions:
        p = p.provision
        provision = await ProvisionTemplate.get(p.provision_template_id) if p.type == 'template' \
            else p

        provisions.append({
            'title': replace_variables_in_value(draft.variables, provision.title),
            'body': replace_variables_in_value(draft.variables, provision.body)
        })

    contract_dict['provisions'] = provisions

    o = await Contract(**contract_dict).create()

    await draft.update({"$set": {"status": ContractDraftStatus.published}})
    return {"message": "Contract Successfully created", "id": o.id}


@contract_router.put("/{id}", response_description="")
async def update(id: str, contract_form: ContractUpdate, user=Depends(get_current_superuser)) -> ContractRead:
    raise HTTPException(status_code=400, detail="No modification on contract")


@contract_router.get("/signature/{signature_id}", response_description="")
async def get_signature(signature_id: str) -> SignatureRead:
    contract = await Contract.find_by_signature_id(signature_id)
    signature = contract.get_signature(signature_id)
    signature_dict = signature.dict()
    signature_dict['contract_label'] = contract.label
    return signature_dict


@contract_router.post("/signature/{signature_id}", response_description="")
async def affix_signature(signature_id: str, signature_file: UploadFile = File(...)) -> bool:
    contract = await Contract.find_by_signature_id(signature_id)

    signature_index = contract.get_signature_index(signature_id)
    signature = contract.parties[signature_index]

    if signature.signature_affixed:
        raise HTTPException(status_code=400, detail="Signature already affixed")

    with open(f'media/signatures/{signature_id}.png', "wb") as buffer:
        shutil.copyfileobj(signature_file.file, buffer)

    update_query = {"$set": {
        f'parties.{signature_index}.signature_affixed': True
    }}
    signature.signature_affixed = True
    if contract.is_signed():
        update_query["$set"]['status'] = 'signed'
    await contract.update(update_query)

    return True
