# Source code of the Ubuntu-it website
# Copyright (C) 2018 Pietro Albini <pietroalbini@ubuntu.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import math
import time

import flask

from uitwww import auth


ACTIONS_PER_PAGE = 25


class PageNotFoundError(BaseException):
    pass


def log(message, session=None):
    """Log an action into the database"""
    date = int(time.time())
    if session is None:
        session = flask.g.auth_id

    flask.current_app.db.update(
        "INSERT INTO actions (session, date, message) VALUES (?, ?, ?);",
        session, date, message,
    )


def list_actions(page=None, session=None):
    """List all the available actions"""
    result = {
        "actions": []
    }

    args = []
    where = ""
    if session is not None:
        where = "WHERE a.session = ?"
        args.append(session)

    limit = ""
    if page is not None:
        page = page - 1
        total = flask.current_app.db.query(
            "SELECT COUNT(*) FROM actions %s;" % where, *args
        )[0][0]

        if page < 0 or page >= math.ceil(total / ACTIONS_PER_PAGE):
            raise PageNotFoundError

        result["current_page"] = page + 1
        result["has_prev"] = page != 0
        result["has_next"] = page + 1 < math.ceil(total / ACTIONS_PER_PAGE)

        limit = "LIMIT ? OFFSET ?"
        args += [ACTIONS_PER_PAGE, page * ACTIONS_PER_PAGE]

    rows = flask.current_app.db.query(
        "SELECT s.nickname, s.ip, s.id, a.date, a.message FROM actions AS a "
        "INNER JOIN auth_sessions AS s ON (s.id = a.session) %s "
        "ORDER BY date DESC %s;" % (where, limit), *args
    )
    for row in rows:
        result["actions"].append({
            "nickname": row[0],
            "ip": row[1],
            "session": row[2],
            "date": row[3],
            "message": row[4],
        })

    return result


def prepare_blueprint(app):
    """Prepare the auth blueprint"""
    bp = flask.Blueprint("actions", __name__)

    @bp.route("/")
    @bp.route("/<int:page>")
    @auth.permission("actions.show")
    def show(page=1):
        try:
            actions = list_actions(page=page)
        except PageNotFoundError:
            return flask.abort(404)

        return flask.render_template(
            "actions/show.html",
            actions=actions,
        )

    return bp
