from flask import session, request, abort
from flask_restplus import Namespace, Resource
from CTFd.models import (
    db,
    Users,
    Solves,
    Awards,
    Tracking,
    Unlocks,
    Submissions,
    Notifications,
)
from CTFd.utils.decorators import authed_only, admins_only, ratelimit
from CTFd.cache import clear_standings
from CTFd.utils.user import get_current_user, is_admin
from CTFd.utils.decorators.visibility import (
    check_account_visibility,
    check_score_visibility,
)

from CTFd.schemas.submissions import SubmissionSchema
from CTFd.schemas.awards import AwardSchema
from CTFd.schemas.users import UserSchema


users_namespace = Namespace("users", description="Endpoint to retrieve Users")


@users_namespace.route("")
class UserList(Resource):
    @check_account_visibility
    def get(self):
        users = Users.query.filter_by(banned=False, hidden=False)
        response = UserSchema(view="user", many=True).dump(users)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    def post(self):
        req = request.get_json()
        schema = UserSchema("admin")
        response = schema.load(req)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        if request.args.get("notify"):
            name = response.data.name
            password = req.get("password")

        clear_standings()

        response = schema.dump(response.data)

        return {"success": True, "data": response.data}


@users_namespace.route("/<int:user_id>")
@users_namespace.param("user_id", "User ID")
class UserPublic(Resource):
    @check_account_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)

        response = UserSchema(view=session.get("type", "user")).dump(user)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        response.data["place"] = user.place
        response.data["score"] = user.score

        return {"success": True, "data": response.data}

    @admins_only
    def patch(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()
        data = request.get_json()
        data["id"] = user_id
        schema = UserSchema(view="admin", instance=user, partial=True)
        response = schema.load(data)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.commit()

        response = schema.dump(response.data)

        db.session.close()

        clear_standings()

        return {"success": True, "data": response}

    @admins_only
    def delete(self, user_id):
        Notifications.query.filter_by(user_id=user_id).delete()
        Awards.query.filter_by(user_id=user_id).delete()
        Unlocks.query.filter_by(user_id=user_id).delete()
        Submissions.query.filter_by(user_id=user_id).delete()
        Solves.query.filter_by(user_id=user_id).delete()
        Tracking.query.filter_by(user_id=user_id).delete()
        Users.query.filter_by(id=user_id).delete()
        db.session.commit()
        db.session.close()

        clear_standings()

        return {"success": True}


@users_namespace.route("/me")
class UserPrivate(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        response = UserSchema("self").dump(user).data
        response["place"] = user.place
        response["score"] = user.score
        return {"success": True, "data": response}

    @authed_only
    def patch(self):
        user = get_current_user()
        data = request.get_json()
        schema = UserSchema(view="self", instance=user, partial=True)
        response = schema.load(data)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        clear_standings()

        return {"success": True, "data": response.data}


@users_namespace.route("/me/solves")
class UserPrivateSolves(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        solves = user.get_solves(admin=True)

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(solves)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}


@users_namespace.route("/me/fails")
class UserPrivateFails(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        fails = user.get_fails(admin=True)

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(fails)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        if is_admin():
            data = response.data
        else:
            data = []
        count = len(response.data)

        return {"success": True, "data": data, "meta": {"count": count}}


@users_namespace.route("/me/awards")
@users_namespace.param("user_id", "User ID")
class UserPrivateAwards(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        awards = user.get_awards(admin=True)

        view = "user" if not is_admin() else "admin"
        response = AwardSchema(view=view, many=True).dump(awards)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}


@users_namespace.route("/<user_id>/solves")
@users_namespace.param("user_id", "User ID")
class UserPublicSolves(Resource):
    @check_account_visibility
    @check_score_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)

        solves = user.get_solves(admin=is_admin())

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(solves)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        #  return {"success": True, "data": response.data}
        return {"success": True, "data": None}


@users_namespace.route("/<user_id>/fails")
@users_namespace.param("user_id", "User ID")
class UserPublicFails(Resource):
    @check_account_visibility
    @check_score_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)
        fails = user.get_fails(admin=is_admin())

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(fails)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        if is_admin():
            data = response.data
        else:
            data = []
        count = len(response.data)

        #  return {"success": True, "data": data, "meta": {"count": count}}
        return {"success": True, "data": None, "meta": {"count": None}}


@users_namespace.route("/<user_id>/awards")
@users_namespace.param("user_id", "User ID or 'me'")
class UserPublicAwards(Resource):
    @check_account_visibility
    @check_score_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)
        awards = user.get_awards(admin=is_admin())

        view = "user" if not is_admin() else "admin"
        response = AwardSchema(view=view, many=True).dump(awards)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        #  return {"success": True, "data": response.data}
        return {"success": True, "data": None}

[(26, 'flask_restplus.Namespace', 'Namespace', False, 'from flask_restplus import Namespace, Resource\n'), (33, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (43, 'flask.request.get_json', 'request.get_json', False, 'from flask import session, request, abort\n'), (44, 'CTFd.schemas.users.UserSchema', 'UserSchema', False, 'from CTFd.schemas.users import UserSchema\n'), (50, 'CTFd.models.db.session.add', 'db.session.add', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (51, 'CTFd.models.db.session.commit', 'db.session.commit', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (53, 'flask.request.args.get', 'request.args.get', False, 'from flask import session, request, abort\n'), (57, 'CTFd.cache.clear_standings', 'clear_standings', False, 'from CTFd.cache import clear_standings\n'), (87, 'flask.request.get_json', 'request.get_json', False, 'from flask import session, request, abort\n'), (89, 'CTFd.schemas.users.UserSchema', 'UserSchema', False, 'from CTFd.schemas.users import UserSchema\n'), (94, 'CTFd.models.db.session.commit', 'db.session.commit', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (98, 'CTFd.models.db.session.close', 'db.session.close', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (100, 'CTFd.cache.clear_standings', 'clear_standings', False, 'from CTFd.cache import clear_standings\n'), (113, 'CTFd.models.db.session.commit', 'db.session.commit', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (114, 'CTFd.models.db.session.close', 'db.session.close', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (116, 'CTFd.cache.clear_standings', 'clear_standings', False, 'from CTFd.cache import clear_standings\n'), (125, 'CTFd.utils.user.get_current_user', 'get_current_user', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (133, 'CTFd.utils.user.get_current_user', 'get_current_user', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (134, 'flask.request.get_json', 'request.get_json', False, 'from flask import session, request, abort\n'), (135, 'CTFd.schemas.users.UserSchema', 'UserSchema', False, 'from CTFd.schemas.users import UserSchema\n'), (140, 'CTFd.models.db.session.commit', 'db.session.commit', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (143, 'CTFd.models.db.session.close', 'db.session.close', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (145, 'CTFd.cache.clear_standings', 'clear_standings', False, 'from CTFd.cache import clear_standings\n'), (154, 'CTFd.utils.user.get_current_user', 'get_current_user', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (170, 'CTFd.utils.user.get_current_user', 'get_current_user', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (178, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (192, 'CTFd.utils.user.get_current_user', 'get_current_user', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (244, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (72, 'flask.abort', 'abort', False, 'from flask import session, request, abort\n'), (213, 'flask.abort', 'abort', False, 'from flask import session, request, abort\n'), (236, 'flask.abort', 'abort', False, 'from flask import session, request, abort\n'), (263, 'flask.abort', 'abort', False, 'from flask import session, request, abort\n'), (34, 'CTFd.schemas.users.UserSchema', 'UserSchema', False, 'from CTFd.schemas.users import UserSchema\n'), (69, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (71, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (86, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (106, 'CTFd.models.Notifications.query.filter_by', 'Notifications.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (107, 'CTFd.models.Awards.query.filter_by', 'Awards.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (108, 'CTFd.models.Unlocks.query.filter_by', 'Unlocks.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (109, 'CTFd.models.Submissions.query.filter_by', 'Submissions.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (110, 'CTFd.models.Solves.query.filter_by', 'Solves.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (111, 'CTFd.models.Tracking.query.filter_by', 'Tracking.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (112, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (157, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (158, 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), (173, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (174, 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), (195, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (196, 'CTFd.schemas.awards.AwardSchema', 'AwardSchema', False, 'from CTFd.schemas.awards import AwardSchema\n'), (210, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (212, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (215, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (217, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (218, 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), (233, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (235, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (237, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (239, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (240, 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), (260, 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), (262, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (264, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (266, 'CTFd.utils.user.is_admin', 'is_admin', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), (267, 'CTFd.schemas.awards.AwardSchema', 'AwardSchema', False, 'from CTFd.schemas.awards import AwardSchema\n'), (126, 'CTFd.schemas.users.UserSchema', 'UserSchema', False, 'from CTFd.schemas.users import UserSchema\n'), (74, 'flask.session.get', 'session.get', False, 'from flask import session, request, abort\n')]