import json

from flask import Blueprint, request, Response
from flask.typing import ResponseReturnValue

from app.extensions import db
from app.models.tfstate import TerraformState

tfstate = Blueprint("tfstate", __name__)


@tfstate.route("/<key>", methods=['GET'])
def handle_get(key: str) -> ResponseReturnValue:
    state = TerraformState.query.filter(TerraformState.key == key).first()
    if state is None or state.state is None:
        return "Not Found", 404
    return Response(state.state, content_type="application/json")


@tfstate.route("/<key>", methods=['POST', 'DELETE', 'UNLOCK'])
def handle_update(key: str) -> ResponseReturnValue:
    state = TerraformState.query.filter(TerraformState.key == key).first()
    if not state:
        if request.method in ["DELETE", "UNLOCK"]:
            return "OK", 200
        state = TerraformState(key=key)
    if state.lock and not (request.method == "UNLOCK" and request.args.get('ID') is None):
        # force-unlock seems to not give an ID to verify so accept no ID being present
        if json.loads(state.lock)['ID'] != request.args.get('ID'):
            return Response(state.lock, status=409, content_type="application/json")
    if request.method == "POST":
        state.state = json.dumps(request.json)
    elif request.method == "DELETE":
        db.session.delete(state)
    elif request.method == "UNLOCK":
        state.lock = None
    db.session.commit()
    return "OK", 200


@tfstate.route("/<key>", methods=['LOCK'])
def handle_lock(key: str) -> ResponseReturnValue:
    state = TerraformState.query.filter(TerraformState.key == key).with_for_update().first()
    if state is None:
        state = TerraformState(key=key, state="")
        db.session.add(state)
    if state.lock is not None:
        lock = state.lock
        db.session.rollback()
        return Response(lock, status=423, content_type="application/json")
    state.lock = json.dumps(request.json)
    db.session.commit()
    return "OK", 200
