from flask import Flask, jsonify, request, make_response, g
from main.models._mapped_tables import CustomGroup as CustomGroupModel
from main.models._mapped_tables import CustomPoint as CustomPointModel

from main.models._mapped_tables import db_selector
from flask_restful import Resource
from setup import DB_SESSION, admin_required, CONFIG
import json

from sqlalchemy.exc import IntegrityError

class CustomGroups(Resource):
    method_decorators = [admin_required]

    def get(self):
        output = []
        for database in CONFIG['databases']['insar']:
            with DB_SESSION[database].begin() as db_session:
                custom_groups = db_session.query(CustomGroupModel).order_by(CustomGroupModel.name).all()

                for custom_group in custom_groups:
                    output.append(custom_group.output | {'database': database})
        return jsonify({"custom_groups": output})

    def post(self, database):
        data = json.loads(request.data)
        custom_group = CustomGroupModel(name=data.get('name'))
        if custom_group.validates is True:
            try:
                with DB_SESSION[db_selector(database)].begin() as db_session:
                    db_session.add(custom_group)
                    db_session.commit()
                    return make_response(jsonify({ "id": custom_group.id, "name": custom_group.name }), 201)
            except IntegrityError:
                return make_response({"message": f"Name '{data.get('name')}' already exists"}, 400)
        else:
            return make_response(jsonify({"message": custom_group.validates}), 400)

class CustomGroup(Resource):
    method_decorators = [admin_required]

    def get(self, database, custom_group_id):
        with DB_SESSION[db_selector(database)].begin() as db_session:
            custom_group = db_session.query(CustomGroupModel).filter(CustomGroupModel.id == custom_group_id).one_or_none()
        
            if not custom_group:
                return make_response(jsonify({}), 404)

            return jsonify(custom_group.output_with_custom_points | {'database': database})

    def put(self, database, custom_group_id):
        data = json.loads(request.data)
        with DB_SESSION[db_selector(database)].begin() as db_session:
            custom_group = db_session.query(CustomGroupModel).filter(CustomGroupModel.id == custom_group_id).one_or_none()

            if not custom_group:
                return make_response({"error": "Custom Point Group not found"}, 404)

        custom_group.name = data.get('name')

        if custom_group.validates is True:
            with DB_SESSION[db_selector(database)].begin() as db_session:
                db_session.add(custom_group)
                db_session.commit()

                return make_response({"message": f"'{custom_group.name}' updated"}, 200)
        else:
            return make_response(jsonify({"error": custom_group.validates}), 400)

    def delete(self, database, custom_group_id):
        with DB_SESSION[db_selector(database)].begin() as db_session:
            custom_points = db_session.query(CustomPointModel).filter(CustomPointModel.custom_group_id == custom_group_id).all()

            custom_group = db_session.query(CustomGroupModel).filter(CustomGroupModel.id == custom_group_id).one_or_none()

            if not custom_group:
                return make_response({"error": "Custom Point Group not found"}, 404)

            try:
                custom_points_message = ''
                if custom_points:
                    for custom_point in custom_points:
                        db_session.delete(custom_point)
                    custom_points_message += f" and {len(custom_points)} points"

                db_session.delete(custom_group)
                db_session.commit()
                return make_response({"message": f"Custom Group '{custom_group.name}'{custom_points_message} deleted"}, 200)
            except IntegrityError:
                return make_response({"message": "Could not delete Custom Point Group - does it have any active Custom Points?"}, 400)



