# Source code of the Ubuntu-it website
# Copyright (C) 2015-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; witout 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 os

import flask

from . import actions
from . import auth
from . import cache
from . import db
from . import download
from . import navbar
from . import pages
from . import redirects
from . import utils


def create_app(data_path):
    """Create a new instance of the application"""
    # Normalize the data path
    data_path = os.path.expanduser(os.path.abspath(data_path))

    app = flask.Flask(
        __name__,
        static_url_path="/+assets",
        instance_path=data_path,
    )

    # Prepare the data directory
    init_data_directory(data_path)

    # Load the secret key
    with open(os.path.join(data_path, "secret_key")) as f:
        app.secret_key = f.read().strip()

    # Initialize the database
    app.db = db.Database(os.path.join(data_path, "database.db"))
    app.db.init()

    app.config["CACHE_PATH"] = os.path.join(data_path, "cache")
    cache.install_cache(app)

    utils.prepare_app(app)

    app.download = download.Downloads(data_path)

    app.register_blueprint(redirects.prepare_blueprint(app))
    app.register_blueprint(app.download.prepare_blueprint(app), url_prefix="/download")
    app.register_blueprint(actions.prepare_blueprint(app), url_prefix="/+actions")
    app.register_blueprint(auth.prepare_blueprint(app), url_prefix="/+auth")
    app.register_blueprint(pages.prepare_blueprint(app))

    nav = navbar.Navbar()
    nav.add_generator("download-distros", app.download.generate_navbar)
    nav.install(app)

    @app.errorhandler(403)
    def forbidden(error):
        return flask.render_template("403.html"), 403

    @app.errorhandler(404)
    def not_found(error):
        return flask.render_template("404.html"), 404

    return app


def init_data_directory(data_path):
    """Initialize the data directory"""
    src_directory = os.path.dirname(os.path.abspath(__file__))

    # Create all the directories
    dirs = ["", "cache"]
    for dir in dirs:
        os.makedirs(os.path.join(data_path, dir), exist_ok=True)

    # Initialize the cache
    static_dirs = {"static": "+assets"}
    for src, dest in static_dirs.items():
        dest = os.path.join(data_path, "cache", dest)

        # Create the correct symlink
        if os.path.exists(dest):
            os.remove(dest)
        os.symlink(os.path.join(src_directory, src), dest)

    # Generate the secret key if not present
    secret_key_path = os.path.join(data_path, "secret_key")
    if not os.path.exists(secret_key_path):
        with open(secret_key_path, "w") as f:
            f.write("%s\n" % utils.random_key(64))
        os.chmod(secret_key_path, 0o400)

    # Initialize the download files
    download_inst = download.Downloads(data_path)
    download_inst.store_cache_file()
