"""Atheneum Flask Application."""
import os
from logging.config import dictConfig

from flask import Flask
from flask_migrate import Migrate

from atheneum.db import db
from atheneum.errors import BaseError, handle_atheneum_base_error, \
    handle_atheneum_404_error
from atheneum.utility import json_utility, session_utility

dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
    }},
    'handlers': {'wsgi': {
        'class': 'logging.StreamHandler',
        'stream': 'ext://flask.logging.wsgi_errors_stream',
        'formatter': 'default'
    }},
    'root': {
        'level': 'INFO',
        'handlers': ['wsgi']
    }
})


def create_app(test_config: dict = None) -> Flask:
    """
    Create an instance of Atheneum.

    :param test_config:
    :return:
    """
    app = Flask(__name__, instance_relative_config=True)
    app.logger.debug('Creating Atheneum Server')

    data_directory = os.getenv('ATHENEUM_DATA_DIRECTORY', '/tmp')
    app.logger.debug('Atheneum Data Directory: %s', data_directory)

    default_database_uri = 'sqlite:///{}/atheneum.db'.format(data_directory)
    app.config.from_mapping(
        SECRET_KEY='dev',
        SQLALCHEMY_DATABASE_URI=default_database_uri,
        SQLALCHEMY_TRACK_MODIFICATIONS=False,
        TRAP_HTTP_EXCEPTIONS=True,
    )

    if test_config is None:
        app.logger.debug('Loading configurations')
        app.config.from_object('atheneum.default_settings')
        app.config.from_pyfile('config.py', silent=True)
        if os.getenv('ATHENEUM_SETTINGS', None):
            app.config.from_envvar('ATHENEUM_SETTINGS')
    else:
        app.logger.debug('Loading test configuration')
        app.config.from_mapping(test_config)

    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    app.json_encoder = json_utility.CustomJSONEncoder
    app.session_interface = session_utility.DisableSessionInterface()

    app.logger.debug('Initializing Application')
    db.init_app(app)
    app.logger.debug('Registering Database Models')
    Migrate(app, db)

    return app


def register_blueprints(app: Flask) -> None:
    """
    Register blueprints for the application.

    :param app:
    :return:
    """
    from atheneum.api import AUTH_BLUEPRINT, USER_BLUEPRINT
    app.register_blueprint(AUTH_BLUEPRINT)
    app.register_blueprint(USER_BLUEPRINT)


def register_error_handlers(app: Flask) -> None:
    """
    Register error handlers for the application.

    :param app:
    :return:
    """
    app.register_error_handler(404, handle_atheneum_404_error)
    app.register_error_handler(BaseError, handle_atheneum_base_error)


atheneum = create_app()  # pylint: disable=C0103
register_blueprints(atheneum)
register_error_handlers(atheneum)

logger = atheneum.logger  # pylint: disable=C0103

if __name__ == "__main__":
    atheneum.run()