import api
import bson
from api.annotations import (
    api_wrapper,
    log_action,
    require_admin,
    require_login,
    require_teacher
)
from api.common import WebError, WebSuccess
from flask import (
    Blueprint,
    Flask,
    render_template,
    request,
    send_from_directory,
    session
)

blueprint = Blueprint("admin_api", __name__)

@blueprint.route('/problems', methods=['GET'])
@api_wrapper
@require_admin
def get_problem_data_hook():
    has_instances = lambda p : len(p["instances"]) > 0
    problems = list(filter(has_instances, api.problem.get_all_problems(show_disabled=True)))

    for problem in problems:
        problem["reviews"] = api.problem_feedback.get_problem_feedback(pid=problem["pid"])

    data = {
        "problems": problems,
        "bundles": api.problem.get_all_bundles()
    }

    return WebSuccess(data=data)

@blueprint.route('/users', methods=['GET'])
@api_wrapper
@require_admin
def get_all_users_hook():
    users = api.user.get_all_users()
    if users is None:
        return WebError("There was an error query users from the database.")
    return WebSuccess(data=users)

@blueprint.route('/exceptions', methods=['GET'])
@api_wrapper
@require_admin
def get_exceptions_hook():
    try:
        limit = abs(int(request.args.get("limit")))
        exceptions = api.admin.get_api_exceptions(result_limit=limit)
        return WebSuccess(data=exceptions)

    except (ValueError, TypeError):
        return WebError("limit is not a valid integer.")

@blueprint.route('/exceptions/dismiss', methods=['POST'])
@api_wrapper
@require_admin
def dismiss_exceptions_hook():
    trace = request.form.get("trace", None)
    if trace:
        api.admin.dismiss_api_exceptions(trace)
        return WebSuccess(data="Successfuly changed exception visibility.")
    else:
        return WebError(message="You must supply a trace to hide.")

@blueprint.route("/problems/submissions", methods=["GET"])
@api_wrapper
@require_admin
def get_problem():
    submission_data = {p["name"]:api.stats.get_problem_submission_stats(pid=p["pid"]) \
                       for p in api.problem.get_all_problems(show_disabled=True)}
    return WebSuccess(data=submission_data)

@blueprint.route("/problems/availability", methods=["POST"])
@api_wrapper
@require_admin
def change_problem_availability_hook():
    pid = request.form.get("pid", None)
    desired_state = request.form.get("state", None)

    if desired_state == None:
        return WebError("Problems are either enabled or disabled.")
    else:
        state = bson.json_util.loads(desired_state)

    api.admin.set_problem_availability(pid, state)
    return WebSuccess(data="Problem state changed successfully.")


@blueprint.route("/shell_servers", methods=["GET"])
@api_wrapper
@require_admin
def get_shell_servers():
    return WebSuccess(data=api.shell_servers.get_servers())

@blueprint.route("/shell_servers/add", methods=["POST"])
@api_wrapper
@require_admin
def add_shell_server():
    params = api.common.flat_multi(request.form)
    api.shell_servers.add_server(params)
    return WebSuccess("Shell server added.")

@blueprint.route("/shell_servers/update", methods=["POST"])
@api_wrapper
@require_admin
def update_shell_server():
    params = api.common.flat_multi(request.form)

    sid = params.get("sid", None)
    if sid is None:
        return WebError("Must specify sid to be updated")

    api.shell_servers.update_server(sid, params)
    return WebSuccess("Shell server updated.")

@blueprint.route("/shell_servers/remove", methods=["POST"])
@api_wrapper
@require_admin
def remove_shell_server():
    sid = request.form.get("sid", None)
    if sid is None:
        return WebError("Must specify sid to be removed")

    api.shell_servers.remove_server(sid)
    return WebSuccess("Shell server removed.")

@blueprint.route("/shell_servers/load_problems", methods=["POST"])
@api_wrapper
@require_admin
def load_problems_from_shell_server():
    sid = request.form.get("sid", None)

    if sid is None:
        return WebError("Must provide sid to load from.")

    number = api.shell_servers.load_problems_from_server(sid)
    return WebSuccess("Loaded {} problems from the server".format(number))

@blueprint.route("/shell_servers/check_status", methods=["GET"])
@api_wrapper
@require_admin
def check_status_of_shell_server():
    sid = request.args.get("sid", None)

    if sid is None:
        return WebError("Must provide sid to load from.")

    all_online, data = api.shell_servers.get_problem_status_from_server(sid)

    if all_online:
        return WebSuccess("All problems are online", data=data)
    else:
        return WebError("One or more problems are offline. Please connect and fix the errors.", data=data)

@blueprint.route("/bundle/dependencies_active", methods=["POST"])
@api_wrapper
@require_admin
def bundle_dependencies():
    bid = request.form.get("bid", None)
    state = request.form.get("state", None)

    if bid is None:
        return WebError("Must provide bid to load from.")

    if state is None:
        return WebError("Must provide a state to set.")

    state = bson.json_util.loads(state)

    api.problem.set_bundle_dependencies_enabled(bid, state)

    return WebSuccess("Dependencies are now {}.".format("enabled" if state else "disabled"))

@blueprint.route("/settings", methods=["GET"])
@api_wrapper
@require_admin
def get_settings():
    return WebSuccess(data=api.config.get_settings())

@blueprint.route("/settings/change", methods=["POST"])
@api_wrapper
@require_admin
def change_settings():
    data = bson.json_util.loads(request.form["json"])
    api.config.change_settings(data)
    return WebSuccess("Settings updated")

[(20, 'flask.Blueprint', 'Blueprint', (['"""admin_api"""', '__name__'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (37, 'api.common.WebSuccess', 'WebSuccess', ([], {'data': 'data'}), False, 'from api.common import WebError, WebSuccess\n'), (43, 'api.user.get_all_users', 'api.user.get_all_users', ([], {}), False, 'import api\n'), (46, 'api.common.WebSuccess', 'WebSuccess', ([], {'data': 'users'}), False, 'from api.common import WebError, WebSuccess\n'), (64, 'flask.request.form.get', 'request.form.get', (['"""trace"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (77, 'api.common.WebSuccess', 'WebSuccess', ([], {'data': 'submission_data'}), False, 'from api.common import WebError, WebSuccess\n'), (83, 'flask.request.form.get', 'request.form.get', (['"""pid"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (84, 'flask.request.form.get', 'request.form.get', (['"""state"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (91, 'api.admin.set_problem_availability', 'api.admin.set_problem_availability', (['pid', 'state'], {}), False, 'import api\n'), (92, 'api.common.WebSuccess', 'WebSuccess', ([], {'data': '"""Problem state changed successfully."""'}), False, 'from api.common import WebError, WebSuccess\n'), (105, 'api.common.flat_multi', 'api.common.flat_multi', (['request.form'], {}), False, 'import api\n'), (106, 'api.shell_servers.add_server', 'api.shell_servers.add_server', (['params'], {}), False, 'import api\n'), (107, 'api.common.WebSuccess', 'WebSuccess', (['"""Shell server added."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (113, 'api.common.flat_multi', 'api.common.flat_multi', (['request.form'], {}), False, 'import api\n'), (119, 'api.shell_servers.update_server', 'api.shell_servers.update_server', (['sid', 'params'], {}), False, 'import api\n'), (120, 'api.common.WebSuccess', 'WebSuccess', (['"""Shell server updated."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (126, 'flask.request.form.get', 'request.form.get', (['"""sid"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (130, 'api.shell_servers.remove_server', 'api.shell_servers.remove_server', (['sid'], {}), False, 'import api\n'), (131, 'api.common.WebSuccess', 'WebSuccess', (['"""Shell server removed."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (137, 'flask.request.form.get', 'request.form.get', (['"""sid"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (142, 'api.shell_servers.load_problems_from_server', 'api.shell_servers.load_problems_from_server', (['sid'], {}), False, 'import api\n'), (149, 'flask.request.args.get', 'request.args.get', (['"""sid"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (154, 'api.shell_servers.get_problem_status_from_server', 'api.shell_servers.get_problem_status_from_server', (['sid'], {}), False, 'import api\n'), (165, 'flask.request.form.get', 'request.form.get', (['"""bid"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (166, 'flask.request.form.get', 'request.form.get', (['"""state"""', 'None'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n'), (174, 'bson.json_util.loads', 'bson.json_util.loads', (['state'], {}), False, 'import bson\n'), (176, 'api.problem.set_bundle_dependencies_enabled', 'api.problem.set_bundle_dependencies_enabled', (['bid', 'state'], {}), False, 'import api\n'), (190, 'bson.json_util.loads', 'bson.json_util.loads', (["request.form['json']"], {}), False, 'import bson\n'), (191, 'api.config.change_settings', 'api.config.change_settings', (['data'], {}), False, 'import api\n'), (192, 'api.common.WebSuccess', 'WebSuccess', (['"""Settings updated"""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (30, 'api.problem_feedback.get_problem_feedback', 'api.problem_feedback.get_problem_feedback', ([], {'pid': "problem['pid']"}), False, 'import api\n'), (34, 'api.problem.get_all_bundles', 'api.problem.get_all_bundles', ([], {}), False, 'import api\n'), (45, 'api.common.WebError', 'WebError', (['"""There was an error query users from the database."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (54, 'api.admin.get_api_exceptions', 'api.admin.get_api_exceptions', ([], {'result_limit': 'limit'}), False, 'import api\n'), (55, 'api.common.WebSuccess', 'WebSuccess', ([], {'data': 'exceptions'}), False, 'from api.common import WebError, WebSuccess\n'), (66, 'api.admin.dismiss_api_exceptions', 'api.admin.dismiss_api_exceptions', (['trace'], {}), False, 'import api\n'), (67, 'api.common.WebSuccess', 'WebSuccess', ([], {'data': '"""Successfuly changed exception visibility."""'}), False, 'from api.common import WebError, WebSuccess\n'), (69, 'api.common.WebError', 'WebError', ([], {'message': '"""You must supply a trace to hide."""'}), False, 'from api.common import WebError, WebSuccess\n'), (75, 'api.stats.get_problem_submission_stats', 'api.stats.get_problem_submission_stats', ([], {'pid': "p['pid']"}), False, 'import api\n'), (87, 'api.common.WebError', 'WebError', (['"""Problems are either enabled or disabled."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (89, 'bson.json_util.loads', 'bson.json_util.loads', (['desired_state'], {}), False, 'import bson\n'), (117, 'api.common.WebError', 'WebError', (['"""Must specify sid to be updated"""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (128, 'api.common.WebError', 'WebError', (['"""Must specify sid to be removed"""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (140, 'api.common.WebError', 'WebError', (['"""Must provide sid to load from."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (152, 'api.common.WebError', 'WebError', (['"""Must provide sid to load from."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (157, 'api.common.WebSuccess', 'WebSuccess', (['"""All problems are online"""'], {'data': 'data'}), False, 'from api.common import WebError, WebSuccess\n'), (159, 'api.common.WebError', 'WebError', (['"""One or more problems are offline. Please connect and fix the errors."""'], {'data': 'data'}), False, 'from api.common import WebError, WebSuccess\n'), (169, 'api.common.WebError', 'WebError', (['"""Must provide bid to load from."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (172, 'api.common.WebError', 'WebError', (['"""Must provide a state to set."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (27, 'api.problem.get_all_problems', 'api.problem.get_all_problems', ([], {'show_disabled': '(True)'}), False, 'import api\n'), (58, 'api.common.WebError', 'WebError', (['"""limit is not a valid integer."""'], {}), False, 'from api.common import WebError, WebSuccess\n'), (76, 'api.problem.get_all_problems', 'api.problem.get_all_problems', ([], {'show_disabled': '(True)'}), False, 'import api\n'), (99, 'api.shell_servers.get_servers', 'api.shell_servers.get_servers', ([], {}), False, 'import api\n'), (184, 'api.config.get_settings', 'api.config.get_settings', ([], {}), False, 'import api\n'), (53, 'flask.request.args.get', 'request.args.get', (['"""limit"""'], {}), False, 'from flask import Blueprint, Flask, render_template, request, send_from_directory, session\n')]