import logging as log
import os
from uuid import UUID

import awsgi
from ariadne import ScalarType
from ariadne import graphql_sync, ObjectType, load_schema_from_path, make_executable_schema, \
    snake_case_fallback_resolvers
from ariadne.constants import PLAYGROUND_HTML
from flask import request, jsonify

from api import app, BASE_ROUTE
from controller import template_controller, repository_controller, project_controller, user_controller
from services.flask_context_service import ContextBuilder, ContextCreationException
from utils.common import build_error_result, get_boolean

BASE_PATH = BASE_ROUTE + 'api'
KEYS_FILE_PATH = os.environ.get('KEYS_FILE_PATH', None)
JWT_VALIDATE_EXPIRATION = get_boolean(os.environ.get('JWT_VALIDATE_EXPIRATION', True))
JWT_VALIDATE_AUDIENCE = get_boolean(os.environ.get('JWT_VALIDATE_AUDIENCE', True))
JWT_AUDIENCE_CLAIM = os.environ.get('JWT_AUDIENCE_CLAIM', 'sub')

if not JWT_VALIDATE_AUDIENCE:
    JWT_AUDIENCE_CLAIM = None

if KEYS_FILE_PATH is not None:
    log.warning("Using local file for public keys %s", KEYS_FILE_PATH)

if not JWT_VALIDATE_EXPIRATION:
    log.warning("JWT expiration validation disabled!")

if not JWT_VALIDATE_AUDIENCE or JWT_AUDIENCE_CLAIM is None:
    log.warning("JWT audience validation disabled!")

ctx_builder = ContextBuilder(keys_file_path=KEYS_FILE_PATH,
                             verify_token_expiration=JWT_VALIDATE_EXPIRATION,
                             audience_claim=JWT_AUDIENCE_CLAIM)

uuid_scalar = ScalarType("UUID")
template_meta_scalar = ScalarType("TemplateMetaData")


@uuid_scalar.serializer
def serialize_uuid(value: UUID):
    return f"{value}"


@uuid_scalar.value_parser
def parse_uuid(value: str):
    if value:
        return UUID(value)
    return None


@uuid_scalar.literal_parser
def parse_uuid_literal(ast):
    value = str(ast.value)
    return parse_uuid(value)


@template_meta_scalar.serializer
def serialize_template_meta(value):
    result = {'uuid': value.uuid,
              'url': value.url,
              'templates': value.meta_data}
    return result


query = ObjectType("Query")

query.set_field('projects', project_controller.get_all_projects)
query.set_field('projectsByOrg', project_controller.get_all_projects_by_org)
query.set_field('project', project_controller.get_project)
query.set_field('repository', repository_controller.get_repository)
query.set_field('organisationalInfo', user_controller.get_user_organisational_info)
query.set_field('userLinks', user_controller.get_user_links)
query.set_field('templateRepositories', template_controller.get_template_repositories)

mutation = ObjectType("Mutation")
mutation.set_field('createProject', project_controller.add_project)
mutation.set_field('updateDescription', project_controller.update_project_data)
mutation.set_field('deleteProject', project_controller.delete_project_from_github)
mutation.set_field('createRepository', repository_controller.add_repository_to_github)
mutation.set_field('deleteRepository', repository_controller.delete_repository_from_github)
mutation.set_field('bindPlutoUser', project_controller.bind_user_to_installation)


type_defs = load_schema_from_path("schema.graphql")
schema = make_executable_schema(
    type_defs, uuid_scalar, template_meta_scalar, query, mutation, snake_case_fallback_resolvers
)


def handler(event, context):
    return awsgi.response(app, event, context)


@app.route(BASE_PATH, methods=["GET"])
def graphql_playground():
    return PLAYGROUND_HTML, 200


@app.route(BASE_PATH, methods=["POST"])
def graphql_server():
    try:
        success, result = graphql_sync(
            schema,
            request.get_json(),
            context_value=ctx_builder.build_context(request),
            debug=app.debug
        )

        if success is True:
            return jsonify(result), 200
        return jsonify([{"message": "Bad Request"}]), 400

    except ContextCreationException as e:
        return jsonify(build_error_result("Bad Request", e)), 400
    except Exception as e:  # pylint: disable=broad-except
        return jsonify(build_error_result("Internal server error", e)), 500


if __name__ == "__main__":
    os.environ['DEBUG'] = "True"
    ctx_builder = ContextBuilder(
        keys_file_path='../test_data/aws_keys.json',
        audience_claim=None,
        verify_token_expiration=False)
    app.run("0.0.0.0", port=8080, debug=True)

import logging as log
import os
from uuid import UUID

import awsgi
from ariadne import ScalarType
from ariadne import graphql_sync, ObjectType, load_schema_from_path, make_executable_schema, \
    snake_case_fallback_resolvers
from ariadne.constants import PLAYGROUND_HTML
from flask import request, jsonify

from api import app, BASE_ROUTE
from controller import template_controller, repository_controller, project_controller, user_controller
from services.flask_context_service import ContextBuilder, ContextCreationException
from utils.common import build_error_result, get_boolean

BASE_PATH = BASE_ROUTE + 'api'
KEYS_FILE_PATH = os.environ.get('KEYS_FILE_PATH', None)
JWT_VALIDATE_EXPIRATION = get_boolean(os.environ.get('JWT_VALIDATE_EXPIRATION', True))
JWT_VALIDATE_AUDIENCE = get_boolean(os.environ.get('JWT_VALIDATE_AUDIENCE', True))
JWT_AUDIENCE_CLAIM = os.environ.get('JWT_AUDIENCE_CLAIM', 'sub')

if not JWT_VALIDATE_AUDIENCE:
    JWT_AUDIENCE_CLAIM = None

if KEYS_FILE_PATH is not None:
    log.warning("Using local file for public keys %s", KEYS_FILE_PATH)

if not JWT_VALIDATE_EXPIRATION:
    log.warning("JWT expiration validation disabled!")

if not JWT_VALIDATE_AUDIENCE or JWT_AUDIENCE_CLAIM is None:
    log.warning("JWT audience validation disabled!")

ctx_builder = ContextBuilder(keys_file_path=KEYS_FILE_PATH,
                             verify_token_expiration=JWT_VALIDATE_EXPIRATION,
                             audience_claim=JWT_AUDIENCE_CLAIM)

uuid_scalar = ScalarType("UUID")
template_meta_scalar = ScalarType("TemplateMetaData")


@uuid_scalar.serializer
def serialize_uuid(value: UUID):
    return f"{value}"


@uuid_scalar.value_parser
def parse_uuid(value: str):
    if value:
        return UUID(value)
    return None


@uuid_scalar.literal_parser
def parse_uuid_literal(ast):
    value = str(ast.value)
    return parse_uuid(value)


@template_meta_scalar.serializer
def serialize_template_meta(value):
    result = {'uuid': value.uuid,
              'url': value.url,
              'templates': value.meta_data}
    return result


query = ObjectType("Query")

query.set_field('projects', project_controller.get_all_projects)
query.set_field('projectsByOrg', project_controller.get_all_projects_by_org)
query.set_field('project', project_controller.get_project)
query.set_field('repository', repository_controller.get_repository)
query.set_field('organisationalInfo', user_controller.get_user_organisational_info)
query.set_field('userLinks', user_controller.get_user_links)
query.set_field('templateRepositories', template_controller.get_template_repositories)

mutation = ObjectType("Mutation")
mutation.set_field('createProject', project_controller.add_project)
mutation.set_field('updateDescription', project_controller.update_project_data)
mutation.set_field('deleteProject', project_controller.delete_project_from_github)
mutation.set_field('createRepository', repository_controller.add_repository_to_github)
mutation.set_field('deleteRepository', repository_controller.delete_repository_from_github)
mutation.set_field('bindPlutoUser', project_controller.bind_user_to_installation)


type_defs = load_schema_from_path("schema.graphql")
schema = make_executable_schema(
    type_defs, uuid_scalar, template_meta_scalar, query, mutation, snake_case_fallback_resolvers
)


def handler(event, context):
    return awsgi.response(app, event, context)


@app.route(BASE_PATH, methods=["GET"])
def graphql_playground():
    return PLAYGROUND_HTML, 200


@app.route(BASE_PATH, methods=["POST"])
def graphql_server():
    try:
        success, result = graphql_sync(
            schema,
            request.get_json(),
            context_value=ctx_builder.build_context(request),
            debug=app.debug
        )

        if success is True:
            return jsonify(result), 200
        return jsonify([{"message": "Bad Request"}]), 400

    except ContextCreationException as e:
        return jsonify(build_error_result("Bad Request", e)), 400
    except Exception as e:  # pylint: disable=broad-except
        return jsonify(build_error_result("Internal server error", e)), 500


if __name__ == "__main__":
    os.environ['DEBUG'] = "True"
    ctx_builder = ContextBuilder(
        keys_file_path='../test_data/aws_keys.json',
        audience_claim=None,
        verify_token_expiration=False)
    app.run("0.0.0.0", port=8080, debug=True)

# pylint: disable=broad-except