from uuid import UUID

from ariadne import convert_kwargs_to_snake_case
from sqlalchemy.exc import IntegrityError, NoResultFound

from api import db
from dao import user_dao, project_dao, organisation_dao, data_origin_dao, user_link_dao
from utils.common import build_result, build_result_from_dict, ServiceException, handle_errors, \
    success_result
from utils.db_common import query_db, update_db


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def get_all_projects(obj, info):  # pylint: disable=unused-argument
    pluto_user_uuid = info.context['pluto_user'].uuid
    return query_db('projects', project_dao.find_all_projects, user_uuid=pluto_user_uuid)


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def get_all_projects_by_org(obj, info, organisation_uuid: UUID):  # pylint: disable=unused-argument
    pluto_user_uuid = info.context['pluto_user'].uuid
    return query_db('projects',
                    project_dao.find_all_projects_by_org,
                    user_uuid=pluto_user_uuid,
                    organisation_uuid=organisation_uuid)


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def get_project(obj, info, project_uuid: UUID):  # pylint: disable=unused-argument
    pluto_user_uuid = info.context['pluto_user'].uuid
    try:
        return query_db(
            'project',
            project_dao.get_project,
            user_uuid=pluto_user_uuid,
            project_uuid=project_uuid)
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def add_project(obj, info, name: str, description: str):  # pylint: disable=unused-argument
    try:
        pluto_user = info.context['pluto_user']
        if project_dao.project_exists(pluto_user, name):
            raise ServiceException(f"Project named {name} already exists for this user")

        proj = project_dao.insert_project(pluto_user=pluto_user,
                                          name=name,
                                          description=description)
        db.session.commit()
        return build_result("project", proj)
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def update_project_data(obj, info, project_uuid: UUID, **update_fields):  # pylint: disable=unused-argument
    try:
        pluto_user_uuid = info.context['pluto_user'].uuid
        project_dao.get_project(user_uuid=pluto_user_uuid, project_uuid=project_uuid)
        result = update_db(
            'project',
            project_dao.update_project,
            user_uuid=pluto_user_uuid,
            project_uuid=project_uuid,
            **update_fields)
        db.session.commit()
        return result
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def delete_project_from_github(obj, info, project_uuid: UUID):  # pylint: disable=unused-argument
    try:
        pluto_user_uuid = info.context['pluto_user'].uuid
        project_dao.get_project(user_uuid=pluto_user_uuid, project_uuid=project_uuid)
        project_dao.delete_project(user_uuid=pluto_user_uuid, project_uuid=project_uuid)
        db.session.commit()
        return success_result()
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def bind_user_to_installation(obj, info, installation_id: str, code: str):  # pylint: disable=unused-argument
    try:
        user = info.context['pluto_user']
        user_uuid = user.uuid
        data_origin = data_origin_dao.get_data_origin_by_name('GitHub')
        project_user = project_dao.get_project_user_by_installation_id(data_origin, installation_id)
        org = organisation_dao.find_org_by_installation_id(data_origin, installation_id)
        org_uuid = org.uuid if org is not None else None
        existing_link = user_link_dao.find_user_link(user_uuid, project_user.uuid, org_uuid)
        if existing_link is None:
            user_dao.bind_users(pluto_user_uuid=user_uuid,
                                project_user_uuid=project_user.uuid,
                                code=code,
                                organisation_uuid=org_uuid)
            db.session.commit()
        return build_result_from_dict({'user_account': user,
                                       'project_user': project_user,
                                       'organisation': org})
    except (NoResultFound, IntegrityError) as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e

from uuid import UUID

from ariadne import convert_kwargs_to_snake_case
from sqlalchemy.exc import IntegrityError, NoResultFound

from api import db
from dao import user_dao, project_dao, organisation_dao, data_origin_dao, user_link_dao
from utils.common import build_result, build_result_from_dict, ServiceException, handle_errors, \
    success_result
from utils.db_common import query_db, update_db


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def get_all_projects(obj, info):  # pylint: disable=unused-argument
    pluto_user_uuid = info.context['pluto_user'].uuid
    return query_db('projects', project_dao.find_all_projects, user_uuid=pluto_user_uuid)


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def get_all_projects_by_org(obj, info, organisation_uuid: UUID):  # pylint: disable=unused-argument
    pluto_user_uuid = info.context['pluto_user'].uuid
    return query_db('projects',
                    project_dao.find_all_projects_by_org,
                    user_uuid=pluto_user_uuid,
                    organisation_uuid=organisation_uuid)


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def get_project(obj, info, project_uuid: UUID):  # pylint: disable=unused-argument
    pluto_user_uuid = info.context['pluto_user'].uuid
    try:
        return query_db(
            'project',
            project_dao.get_project,
            user_uuid=pluto_user_uuid,
            project_uuid=project_uuid)
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def add_project(obj, info, name: str, description: str):  # pylint: disable=unused-argument
    try:
        pluto_user = info.context['pluto_user']
        if project_dao.project_exists(pluto_user, name):
            raise ServiceException(f"Project named {name} already exists for this user")

        proj = project_dao.insert_project(pluto_user=pluto_user,
                                          name=name,
                                          description=description)
        db.session.commit()
        return build_result("project", proj)
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def update_project_data(obj, info, project_uuid: UUID, **update_fields):  # pylint: disable=unused-argument
    try:
        pluto_user_uuid = info.context['pluto_user'].uuid
        project_dao.get_project(user_uuid=pluto_user_uuid, project_uuid=project_uuid)
        result = update_db(
            'project',
            project_dao.update_project,
            user_uuid=pluto_user_uuid,
            project_uuid=project_uuid,
            **update_fields)
        db.session.commit()
        return result
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def delete_project_from_github(obj, info, project_uuid: UUID):  # pylint: disable=unused-argument
    try:
        pluto_user_uuid = info.context['pluto_user'].uuid
        project_dao.get_project(user_uuid=pluto_user_uuid, project_uuid=project_uuid)
        project_dao.delete_project(user_uuid=pluto_user_uuid, project_uuid=project_uuid)
        db.session.commit()
        return success_result()
    except NoResultFound as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e


@convert_kwargs_to_snake_case
@handle_errors(db.session)
def bind_user_to_installation(obj, info, installation_id: str, code: str):  # pylint: disable=unused-argument
    try:
        user = info.context['pluto_user']
        user_uuid = user.uuid
        data_origin = data_origin_dao.get_data_origin_by_name('GitHub')
        project_user = project_dao.get_project_user_by_installation_id(data_origin, installation_id)
        org = organisation_dao.find_org_by_installation_id(data_origin, installation_id)
        org_uuid = org.uuid if org is not None else None
        existing_link = user_link_dao.find_user_link(user_uuid, project_user.uuid, org_uuid)
        if existing_link is None:
            user_dao.bind_users(pluto_user_uuid=user_uuid,
                                project_user_uuid=project_user.uuid,
                                code=code,
                                organisation_uuid=org_uuid)
            db.session.commit()
        return build_result_from_dict({'user_account': user,
                                       'project_user': project_user,
                                       'organisation': org})
    except (NoResultFound, IntegrityError) as e:
        db.session.rollback()
        raise ServiceException("Bad Request") from e

# pylint: disable=unused-argument # pylint: disable=unused-argument # pylint: disable=unused-argument # pylint: disable=unused-argument # pylint: disable=unused-argument # pylint: disable=unused-argument # pylint: disable=unused-argument