import base64
import json
import logging
import os
import sys
import time
import uuid
import click
from datetime import date, timedelta, datetime, timezone
from logging.handlers import TimedRotatingFileHandler
from pathlib import Path

from flask import (
    Flask, session, redirect, request,
    send_from_directory, send_file, jsonify
)
from flask_jwt_extended import JWTManager, jwt_required
from core.websocket_handler import init_websocket
from core.mqtt_handler import init_mqtt
from flask_wtf.csrf import CSRFError

from median.views import RawConfig

from common.command import register_commands
from common.database import sync_profil
from common.status import HTTP_404_NOT_FOUND, HTTP_401_UNAUTHORIZED, \
    HTTP_200_OK, HTTP_301_MOVED_PERMANENTLY
from common.translations import generate_resources_files, generate_translations_files, generate_translations_lang
from ressources.acced.acced_batch_blueprint import acced_batch_blueprint
from ressources.acced.acced_blueprint import acced_blueprint
from ressources.acced.acced_consumption_blueprint import acced_consumption_blueprint
from ressources.acced.acced_message_blueprint import acced_message_blueprint
from ressources.acced.acced_output_blueprint import acced_output_blueprint
from ressources.acced.acced_reappro_blueprint import acced_reappro_blueprint
from ressources.acced.acced_replenish_blueprint import acced_replenish_blueprint
from ressources.acced.acced_saved_blueprint import acced_saved_blueprint
from ressources.acced.acced_setting_message_blueprint import acced_setting_message_blueprint
from ressources.acced.acced_without_threshold_blueprint import acced_without_threshold_blueprint
from ressources.acced.block_cause.block_cause_blueprint import block_causes_blueprint
from ressources.acced.production.acced_production_blueprint import acced_production_blueprint
from ressources.acced.ward_blueprint import ward_blueprint
from ressources.astus.astus_blueprint import astus_blueprint
from ressources.astus.consumption.astus_consumption_blueprint import astus_consumption_blueprint
from ressources.astus.astus_drawer_blueprint import astus_drawer_blueprint
from ressources.astus.astus_filled_blueprint import astus_filled_blueprint
from ressources.astus.astus_logs_blueprint import astus_logs_blueprint
from ressources.astus.astus_nurse_stock_blueprint import astus_nurse_stock_blueprint
from ressources.astus.astus_output_blueprint import astus_output_blueprint
from ressources.astus.astus_stat_blueprint import astus_stats_blueprint
from ressources.astus.astus_stock_blueprint import astus_stock_blueprint
from ressources.astus.astus_ward_blueprint import astus_ward_blueprint
from ressources.blueprint.account_blueprint import account_blueprint
from ressources.blueprint.actions_blueprint import actions_blueprint
from ressources.blueprint.adress_blueprint import address_blueprint
from ressources.blueprint.available_adresses_blueprint import available_adresses_blueprint
from ressources.blueprint.batch_blueprint import batch_blueprint
from ressources.blueprint.blocked_history.blocked_history_blueprint import blocked_history_blueprint
from ressources.blueprint.blocking_defects_blueprint import blocking_defects_blueprint
from ressources.blueprint.catalog_blueprint import catalog_blueprint
from ressources.blueprint.cip_blueprint import cip_blueprint
from ressources.blueprint.completion_blueprint import completion_blueprint
from ressources.blueprint.config.config_blueprint import config_blueprint
from ressources.blueprint.container_format_blueprint import container_format_blueprint
from ressources.blueprint.external.external_blueprint import external_blueprint
from ressources.blueprint.external.external_replenish_blueprint import external_replenish_blueprint
from ressources.blueprint.external.external_stock_blueprint import external_stock_blueprint
from ressources.blueprint.external.external_unload_blueprint import external_unload_blueprint
from ressources.blueprint.feasibility_blueprint import feasibility_blueprint
from ressources.blueprint.form_blueprint import form_blueprint
from ressources.blueprint.format_blueprint import format_blueprint
from ressources.blueprint.global_blueprint import global_blueprint
from ressources.blueprint.global_output_blueprint import global_output_blueprint
from ressources.blueprint.gtin_blueprint import gtin_blueprint
from ressources.blueprint.gtin_cip_blueprint import gtin_cip_blueprint
from ressources.blueprint.historic_blueprint import historic_blueprint
from ressources.blueprint.importref.import_ref_blueprint import importref_blueprint
from ressources.blueprint.input_lists_blueprint import input_lists_blueprint
from ressources.blueprint.interface_blueprint import interface_blueprint
from ressources.blueprint.inventory_blueprint import inventory_blueprint
from ressources.blueprint.languages_blueprint import languages_blueprint
from ressources.blueprint.locations.locations_blueprint import locations_blueprint
from ressources.blueprint.move_container_blueprint import move_container_blueprint
from ressources.blueprint.organilog_ticket_blueprint import organilog_ticket_blueprint
from ressources.blueprint.peigne_blueprint import peignes_blueprint
from ressources.blueprint.prescriptions_blueprint import prescriptions_blueprint
from ressources.blueprint.product_blueprint import product_blueprint
from ressources.blueprint.profil_blueprint import profils_blueprint
from ressources.blueprint.reference_blueprint import reference_blueprint
from ressources.blueprint.replenishment_blueprint import replenishment_blueprint
from ressources.blueprint.reporting_blueprint import reporting_blueprint
from ressources.blueprint.riedl_blueprint import riedl_blueprint
from ressources.blueprint.rights_blueprint import rights_blueprint
from ressources.blueprint.stock.ref_stock_blueprint import ref_stock_blueprint
from ressources.blueprint.stock_blueprint import stock_blueprint
from ressources.blueprint.store_blueprint import store_blueprint
from ressources.blueprint.stores.stores_blueprint import stores_blueprint
from ressources.blueprint.suggestions_blueprint import suggestions_blueprint
from ressources.blueprint.threshold.threshold_blueprint import threshold_blueprint
from ressources.blueprint.threshold_simulator.threshold_sim_blueprint import threshold_sim_blueprint
from ressources.blueprint.traceability_blueprint import traceability_blueprint
from ressources.blueprint.trends_blueprint import trends_blueprint
from ressources.blueprint.unit_blueprint import unit_blueprint
from ressources.blueprint.user_blueprint import user_blueprint
from ressources.blueprint.users_blueprint import users_blueprint
from ressources.blueprint.wards_blueprint import wards_blueprint
from ressources.blueprint.withdrawnbatch_blueprint import withdrawnbatch_blueprint
from ressources.blueprint.patients_blueprint import patients_blueprint
from ressources.blueprint.maggroups_blueprint import maggroups_blueprint
from ressources.blueprint.printers.printer_blueprint import printer_blueprint
from ressources.riedls.riedl_input_blueprint import riedl_input_blueprint
from ressources.riedls.riedl_output_blueprint import riedl_output_blueprint
from ressources.riedls.riedl_output_list_blueprint import riedl_output_list_blueprint
from ressources.riedls.riedl_stock_blueprint import riedl_stock_blueprint
from ressources.riedls.riedl_taking_mode_blueprint import riedl_taking_mode_blueprint
from ressources.blueprint.transfert.transfert_blueprint import transferts_blueprint
from ressources.astus.multidoses.astus_multidoses_blueprint import astus_multidoses_blueprint
from ressources.blueprint.dpm.dpm_blueprint import dpm_blueprint
from ressources.aideplus.aideplus_blueprint import aideplus_blueprint
from ressources.aideplus.aideplus_completion_blueprint import aideplus_completion_blueprint
from ressources.blueprint.list_blueprint import list_blueprint
from ressources.tools.tools_workitems import tools_workitems
from ressources.tools.tools_interfaces import tools_interfaces
from ressources.blueprint.generic.logging_blueprint import logging_blueprint
from ressources.blueprint.external.external_returns import external_returns_blueprint
from ressources.devices.devices_blueprint import devices_blueprint
from ressources.blueprint.data.datafetcher_blueprint import data_fetcher_blueprint
from common.session import (
    init_session, handle_csrf_error, get_csrf_token,
    login_user, logout_user, refresh_token, check_session_status,
    generate_public_key, init_user_password, renew_password,
    refresh_session_time
)


class MedianJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, date):
            return o.isoformat()

        return super().default(o)


# Les fichiers HTML sont fournis en statique.
html_dir = os.environ.get('MEDIAN_HTML_DIR', os.path.join('..', '..', 'frontend', 'dist'))
static_dir = os.environ.get('MEDIAN_STATIC_DIR', os.path.join('..', '..', 'frontend', 'dist', 'assets'))

# Le fichier de log se configure dans IIS

# Ajouter Variable LOG_CONSOLE si on veut le log en console
if os.environ.get("LOG_CONSOLE", False):
    logging.basicConfig(level=logging.INFO)

# The log file must be rotate automatically at midninght
log_file = os.environ.get('MEDIAN_LOG_FILE', 'medianweb.log')
tfh = TimedRotatingFileHandler(log_file, when="midnight", encoding='utf-8')

log_level = os.environ.get('LOGGING_LEVEL', logging.DEBUG)
logging.basicConfig(
    handlers=[tfh],
    level=log_level,
    format='%(asctime)s  %(name)-20s  %(levelname)-6s: %(message)s'
)
logger = logging.getLogger('median.webserver')

app = Flask(__name__)
# scheduler = APScheduler()

# Initialize WebSocket
sock = init_websocket(app)

if os.environ.get("MEDIAN_MQTT_ENABLED", "0") == "1":
    # MQTT Configuration
    if os.environ.get('MEDIAN_MQTT_BROKER_URL') is None or \
       os.environ.get('MEDIAN_MQTT_BROKER_PORT') is None:
        logger.error("MQTT broker URL and port must be set in environment variables")
        sys.exit(1)
    app.config['MEDIAN_MQTT_BROKER_URL'] = os.environ.get('MEDIAN_MQTT_BROKER_URL')
    app.config['MEDIAN_MQTT_BROKER_PORT'] = int(os.environ.get('MEDIAN_MQTT_BROKER_PORT'))
    mqtt = init_mqtt(app)

app.config["JWT_SECRET_KEY"] = os.environ.get(
    'MEDIAN_JWT_SECRET_KEY', base64.b64encode(str(uuid.uuid4()).encode('ascii')))
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(minutes=30)
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=1)
app.config['SOCK_SERVER_OPTIONS'] = {'ping_interval': 25}

jwt = JWTManager(app)

# Generic Blueprint
app.register_blueprint(account_blueprint, url_prefix='/api/account')
app.register_blueprint(ward_blueprint, url_prefix='/api/ward')
app.register_blueprint(wards_blueprint, url_prefix='/api/services')
app.register_blueprint(product_blueprint, url_prefix='/api/product')
app.register_blueprint(prescriptions_blueprint, url_prefix='/api/prescriptions')
app.register_blueprint(organilog_ticket_blueprint, url_prefix='/api/tickets')
app.register_blueprint(historic_blueprint, url_prefix='/api/historic')
app.register_blueprint(interface_blueprint, url_prefix='/api/interface')
app.register_blueprint(withdrawnbatch_blueprint, url_prefix='/api/withdrawnbatch')
app.register_blueprint(cip_blueprint, url_prefix='/api/cip')
app.register_blueprint(rights_blueprint, url_prefix='/api/rights')
app.register_blueprint(reference_blueprint, url_prefix='/api/reference')
app.register_blueprint(unit_blueprint, url_prefix='/api/unit')
app.register_blueprint(form_blueprint, url_prefix='/api/forme')
app.register_blueprint(format_blueprint, url_prefix='/api/format')
app.register_blueprint(languages_blueprint, url_prefix='/api/languages')
app.register_blueprint(traceability_blueprint, url_prefix='/api/traceability')
app.register_blueprint(inventory_blueprint, url_prefix='/api/inventory')
app.register_blueprint(user_blueprint, url_prefix='/api/user')
app.register_blueprint(profils_blueprint, url_prefix='/api/profils')
app.register_blueprint(suggestions_blueprint, url_prefix='/api/suggestions')
app.register_blueprint(stock_blueprint, url_prefix='/api/stock')
app.register_blueprint(container_format_blueprint, url_prefix='/api/container_formats')
app.register_blueprint(available_adresses_blueprint, url_prefix='/api/available_adresses')
app.register_blueprint(address_blueprint, url_prefix='/api/adresse')
app.register_blueprint(move_container_blueprint, url_prefix='/api/move_container')
app.register_blueprint(threshold_blueprint, url_prefix='/api/seuils')
app.register_blueprint(input_lists_blueprint, url_prefix='/api/liste_entrees')
app.register_blueprint(gtin_blueprint, url_prefix='/api/ucd')
app.register_blueprint(gtin_cip_blueprint, url_prefix='/api/ucd_cip')
app.register_blueprint(replenishment_blueprint, url_prefix='/api/replenishment')
app.register_blueprint(reporting_blueprint, url_prefix='/api/reporting')
app.register_blueprint(global_output_blueprint, url_prefix='/api/sortie_globale')
app.register_blueprint(global_blueprint, url_prefix='/api/globale')
app.register_blueprint(actions_blueprint, url_prefix='/api/actions')
app.register_blueprint(threshold_sim_blueprint, url_prefix='/api/threshold_sim')
app.register_blueprint(feasibility_blueprint, url_prefix='/api/feasibility')
app.register_blueprint(importref_blueprint, url_prefix='/api/importref')
app.register_blueprint(blocking_defects_blueprint, url_prefix='/api/blockingdefects')
app.register_blueprint(catalog_blueprint, url_prefix='/api/catalog')
app.register_blueprint(batch_blueprint, url_prefix='/api/batch')
app.register_blueprint(blocked_history_blueprint, url_prefix='/api/blockedhistoric')
app.register_blueprint(ref_stock_blueprint, url_prefix='/api/reference/stock')
app.register_blueprint(patients_blueprint, url_prefix='/api/patients')
app.register_blueprint(transferts_blueprint, url_prefix='/api/transfert')
app.register_blueprint(printer_blueprint, url_prefix='/api/printers')

# Parameters Blueprint
app.register_blueprint(users_blueprint, url_prefix='/api/users')
app.register_blueprint(peignes_blueprint, url_prefix='/api/peignes')
app.register_blueprint(config_blueprint, url_prefix='/api/config')
app.register_blueprint(maggroups_blueprint, url_prefix='/api/maggroups')

# Administration Blueprint
app.register_blueprint(dpm_blueprint, url_prefix='/api/dpm')
app.register_blueprint(completion_blueprint, url_prefix='/api/completion')

# Acced Blueprint
app.register_blueprint(acced_production_blueprint, url_prefix='/api/acced/prod')
app.register_blueprint(locations_blueprint, url_prefix='/api/emplacements')
app.register_blueprint(acced_output_blueprint, url_prefix='/api/acced/output')
app.register_blueprint(acced_reappro_blueprint, url_prefix='/api/acced/reappro')
app.register_blueprint(acced_consumption_blueprint, url_prefix='/api/acced/consumption')
app.register_blueprint(acced_batch_blueprint, url_prefix='/api/acced/batch')
app.register_blueprint(acced_message_blueprint, url_prefix='/api/acced/message')
app.register_blueprint(acced_setting_message_blueprint, url_prefix='/api/acced/settings/messages')
app.register_blueprint(acced_blueprint, url_prefix='/api/acced')
app.register_blueprint(acced_without_threshold_blueprint, url_prefix='/api/acced/cwothreshold')
app.register_blueprint(acced_replenish_blueprint, url_prefix='/api/listes_reappro')
app.register_blueprint(trends_blueprint, url_prefix='/api/trends')
app.register_blueprint(acced_saved_blueprint, url_prefix='/api/acced/savedlist')
app.register_blueprint(block_causes_blueprint, url_prefix='/api/acced/block')


# Blueprint for ASTUS
app.register_blueprint(astus_blueprint, url_prefix='/api/astus')
app.register_blueprint(astus_ward_blueprint, url_prefix='/api/astus/param/ward')
app.register_blueprint(astus_logs_blueprint, url_prefix='/api/astus/logs')
app.register_blueprint(astus_stock_blueprint, url_prefix='/api/astus/stock')
app.register_blueprint(astus_filled_blueprint, url_prefix='/api/astus/replenish')
app.register_blueprint(astus_drawer_blueprint, url_prefix='/api/astus/drawer')
app.register_blueprint(astus_nurse_stock_blueprint, url_prefix='/api/astus/nursestock')
app.register_blueprint(astus_output_blueprint, url_prefix='/api/astus/output')
app.register_blueprint(astus_consumption_blueprint, url_prefix='/api/astus/consumption')
app.register_blueprint(astus_stats_blueprint, url_prefix='/api/astus/stats')
app.register_blueprint(astus_multidoses_blueprint, url_prefix='/api/astus/multidoses')

# Blueprint for Riedl
app.register_blueprint(riedl_blueprint, url_prefix='/api/riedl')
app.register_blueprint(riedl_taking_mode_blueprint, url_prefix='/api/riedl/takingmode')
app.register_blueprint(riedl_output_blueprint, url_prefix='/api/riedl/output')
app.register_blueprint(riedl_output_list_blueprint, url_prefix='/api/riedl/output/list')
app.register_blueprint(riedl_input_blueprint, url_prefix='/api/riedl/input')
app.register_blueprint(riedl_stock_blueprint, url_prefix='/api/riedl/stock')

# Blueprint for external
app.register_blueprint(external_blueprint, url_prefix='/api/external')
app.register_blueprint(external_stock_blueprint, url_prefix='/api/external/stock')
app.register_blueprint(external_replenish_blueprint, url_prefix='/api/external/replenish')
app.register_blueprint(external_unload_blueprint, url_prefix='/api/external/unload')
app.register_blueprint(external_returns_blueprint, url_prefix='/api/external/returns')

# Blueprint for store
app.register_blueprint(store_blueprint, url_prefix='/api/magasin')
app.register_blueprint(stores_blueprint, url_prefix='/api/magasins')

# Blueprints for Aide-Plus
app.register_blueprint(aideplus_blueprint, url_prefix='/api/aideplus')
app.register_blueprint(aideplus_completion_blueprint, url_prefix='/api/aideplus/completion')

# Generic blueprints for common components
app.register_blueprint(list_blueprint, url_prefix='/api/list')
app.register_blueprint(logging_blueprint, url_prefix='/api/logging')

# Blueprints for TOOLS
app.register_blueprint(tools_interfaces, url_prefix='/api/tools/interfaces')
app.register_blueprint(tools_workitems,  url_prefix='/api/tools/work_items')

# Blueprints for DEVICES
app.register_blueprint(devices_blueprint, url_prefix='/api/devices')

# Blueprints for data management
app.register_blueprint(data_fetcher_blueprint, url_prefix='/api/datafetcher')


init_session(app)

register_commands(app)

# scheduler.init_app(app)
# scheduler.start()


@app.before_request
def before_request():
    """Use for reverse proxy with https enabled"""
    excluded_paths = {
        'ws/riedl',
        'api/session',
    }

    if any(path in request.url for path in excluded_paths):
        return

    try:
        if request.url.endswith('/') or '/assets/' in request.url:
            pass
        elif (not request.url.endswith('ftoken') and
              not request.url.endswith('login') and
              not request.url.endswith('publickey') and
              not request.url.endswith('refresh-token') and
              not request.url.endswith('manifest.json')):
            if session.get('last_action_time'):
                # Check session timeout
                elapsed_time = datetime.now(timezone.utc) - session['last_action_time']
                if elapsed_time.total_seconds() > app.permanent_session_lifetime.total_seconds():
                    return {"message": "session.expired"}, HTTP_401_UNAUTHORIZED

            session['last_action_time'] = datetime.now(timezone.utc)
    except Exception as e:
        logger.error('before request : ' + e.args)
        return {'message': 'connection.failed'}, HTTP_401_UNAUTHORIZED

    scheme = request.headers.get('X-Forwarded-Proto')
    if scheme and scheme.lower() == 'http' and request.url.startswith('http://'):
        url = request.url.replace('http://', 'https://', 1)
        code = HTTP_301_MOVED_PERMANENTLY
        return redirect(url, code=code)


@app.errorhandler(404)
def page_not_found(e):
    """
    When we use F5 to refresh the browser, it returns 404
    we need to serve the Vue app's index.html to enable client-side routing
    """
    return send_from_directory(html_dir, 'index.html')


@app.route('/')
def home():
    """Redirect to the index.html page"""
    return send_from_directory(html_dir, 'index.html')
    # return redirect('/index.html')


@app.route('/home')
def homepage():
    """Launch the homepage,
    TODO: Can be defined per user
    """
    if not session.get('username', False):
        return redirect('/login')
    return redirect('/reference.html')


@app.errorhandler(CSRFError)
def csrf_error_handler(e):
    return handle_csrf_error(e)


# Session and Authentication routes
# TODO: remove after fix all type in frontend
@app.route('/crsftoken', methods=['GET'])
def inject_crsf_token():
    print("WARNING: use /csrftoken instead !!!")
    return get_csrf_token()


@app.route('/csrftoken', methods=['GET'])
def inject_csrf_token():
    return get_csrf_token()


@app.route('/inituserpassword', methods=['POST'])
def inituserpassword():
    if request.method == 'POST':
        user_id = request.form['userid']
        return init_user_password(user_id)


@app.route('/renewpassword', methods=['POST'])
def renewpassword():
    if request.method == 'POST':
        password = request.form['password']
        confirm = request.form['password_confirmation']
        return renew_password(password, confirm)


@app.route("/publickey", methods=["POST"])
def public_key_generate():
    return generate_public_key()


@app.route("/refresh-token", methods=["POST"])
@jwt_required(refresh=True)
def refresh():
    return refresh_token()


@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        return login_user()
    return redirect('/login.html')


@app.route('/logout')
def logout():
    return logout_user()


@app.route('/api/session', methods=['GET'])
def check_session():
    return check_session_status()


@app.route('/api/session/refresh', methods=['POST'])
def refresh_session():
    return refresh_session_time()


@app.route('/manifest.json', methods=['GET'])
def manifest():
    icons_size = [(48, 48), (72, 72), (96, 96), (144, 144), (168, 168), (192, 192)]
    icons = []
    for i in icons_size:
        icons.append({
            "src": "/assets/logo_mweb-%ix%i.png" % (i[0], i[1]),
            "sizes": "%ix%i" % (i[0], i[1]),
            "type": "image/png"
        })

    res = {
        "name": "MedianWeb 2",
        "short_name": "MedianWeb",
        "start_url": "/?utm_source=web_app_manifest",
        "display": "standalone",
        "background_color": "#2e86c1",
        "icons": icons
    }
    return res, HTTP_200_OK


@app.route('/static/<path:chemin>', methods=['GET'])
def fichier_static(chemin):
    """On recupere et renvoi les fichiers statiques tel quel"""
    return send_from_directory(static_dir, chemin)


@app.route('/assets/<path:chemin>', methods=['GET'])
def fichier_assets(chemin):
    """On recupere et renvoi les fichiers statiques tel quel"""
    mimetype = 'text/plain'
    if request.url.endswith('.js'):
        mimetype = 'application/javascript'
    elif request.url.endswith('.css'):
        mimetype = 'text/css'
    elif request.url.endswith('.woff2'):
        mimetype = 'font/woff2'
    elif request.url.endswith('.png'):
        mimetype = 'image/png'
    elif request.url.endswith('.jpg'):
        mimetype = 'image/jpeg'
    elif request.url.endswith('.svg'):
        mimetype = 'image/svg+xml'
    return send_from_directory(static_dir, chemin, mimetype=mimetype)


@app.route('/<path:chemin>', methods=['GET'])
def fichier_html(chemin):
    """On recupere et renvoi les page HTML telle quelle"""
    try:
        mimetype = 'text/plain'
        if request.url.endswith('.js'):
            mimetype = 'application/javascript'
        elif request.url.endswith('.css'):
            mimetype = 'text/css'
        elif request.url.endswith('.woff2'):
            mimetype = 'font/woff2'
        elif request.url.endswith('.png'):
            mimetype = 'image/png'
        elif request.url.endswith('.jpg'):
            mimetype = 'image/jpeg'
        elif request.url.endswith('.svg'):
            mimetype = 'image/svg+xml'
        return send_from_directory(html_dir, chemin, mimetype=mimetype)
    except Exception as e:
        # If URL not end by /, it's en URL generate by vue, we just redirect to the root
        if not request.url.endswith('/'):
            return redirect('/')
        else:
            logger.error(f'Error serving file {chemin}: {str(e)}')
            return {'message': 'Error serving file'}, HTTP_404_NOT_FOUND


@app.route('/status', methods=['GET'])
@jwt_required()
def app_status():
    """retourne les informations utiles au debuggage"""
    if not session.get('username', False):
        return redirect('/login')

    monitoring_token = RawConfig().read("k_eco_monitoring_token")
    monitoring_server = RawConfig().read("k_eco_monitoring_serveur")  # Poste
    monitoring_url_config = RawConfig().read("k_eco_monitoring")  # URL
    monitoring_url = monitoring_url_config.value.replace('heartbeat.php', 'report.php') if monitoring_url_config else ''

    dbinfo = {
        'name': os.environ.get('MEDIAN_DB_NAME', 'unknown'),
        'server': os.environ.get('MEDIAN_DB_HOST', 'unknown'),
        'user': os.environ.get('MEDIAN_DB_USER', 'unknown'),
        'port': os.environ.get('MEDIAN_DB_PORT', 'unknown'),
    }
    pyinfo = {
        'version': sys.version,
        'major': sys.version_info.major,
        'minor': sys.version_info.minor,
        'micro': sys.version_info.micro,
        'release': sys.version_info.releaselevel,
        'path': os.environ.get('PYTHONPATH', 'N/A'),
        'wsgi': os.environ.get('WSGI_HANDLER', 'N/A'),
    }
    version = {
        "Major": 0,
        "Minor": 0,
        "Patch": 0,
        "MajorMinorPatch": "0.0.0",
    }
    config = {
        "monitoring_token": monitoring_token.value if monitoring_token else '',
        "monitoring_server": monitoring_server.value if monitoring_server else '',
        "monitoring_url": monitoring_url,
    }
    version_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'version.json')
    logger.debug(version_file)
    if os.path.exists(version_file):
        with open(version_file, 'r') as f:
            # logger.debug(f.read())
            f.seek(0)
            version = json.loads(f.read())
    else:
        logger.error("version file not found")

    return jsonify(database=dbinfo, python=pyinfo, version=version, config=config), HTTP_200_OK


@app.route('/download/<string:filename>')
def download_file(filename):
    args = request.args
    val = args.get("attachment")
    attachment = (val is not None)
    cr_folder = os.environ.get('REPORTING_FOLDER', '.')
    fp = Path(cr_folder).joinpath(filename)
    if not fp.exists():
        logger.error('Download: file %s not found!' % filename)
        return {'message': 'File not found', 'filename': filename}, HTTP_404_NOT_FOUND
    return send_file(fp, as_attachment=attachment)


@app.cli.command("migrate")
@click.option('--force', '-f', is_flag=True, help="Delete web_tables, before recreate")
@click.option('--transform-charset', '-t', is_flag=True, help="Convert all tables to the correct charset")
def migrate_app(force=False, transform_charset=False):
    """Update database catalog"""
    from common.database import (check_model, delete_model, sync_menu, median_upgrade, medianweb_upgrade,
                                 median_information, convert_charset)
    from common.models import (WebLang, WebMenu, WebMenuTranslation, WebForm, WebLogActions,
                               WebThresholdSheet, WebThresholdParameter, WebImportRefHeader,
                               WebImportRefLine)
    from common.migration import add_default_rights
    dbi = median_information()
    print('Database information\nHost: %(server)s\nPort: %(port)s\nName: %(name)s\nUser: %(user)s\n-----------' % dbi)
    if force:
        print("Force mode detected, delete tables before recreate\n-----------")
        delete_model('web_form_i18n', WebForm)
        delete_model('web_menu_i18n', WebMenuTranslation)
        delete_model('web_menu', WebMenu)
        delete_model('web_lang', WebLang)

    if transform_charset:
        print("Charset transformation activated\n-----------")
        convert_charset()

    check_model('web_lang', WebLang, 'web_lang.json')
    check_model('web_menu', WebMenu, 'web_menu.json')
    sync_menu('web_menu', WebMenu, 'web_menu.json')
    check_model('web_menu_i18n', WebMenuTranslation)
    check_model('web_form_i18n', WebForm)
    check_model('web_log_actions', WebLogActions)
    check_model('web_threshold_sheet', WebThresholdSheet)
    check_model('web_threshold_parameter', WebThresholdParameter)
    check_model('web_importref_header', WebImportRefHeader)
    check_model('web_importref_line', WebImportRefLine)
    median_upgrade(force)
    medianweb_upgrade(force)
    sync_profil()
    add_default_rights()
    print('Migration done')


@app.cli.command("init")
def init_data():
    """Add initiate data"""
    from common.database import median_information
    from common.migration import add_default_libelle, add_default_rights, add_default_interfaces, add_default_counter
    print("Initilize datas")
    dbi = median_information()
    print('Database information\nHost: %(server)s\nPort: %(port)s\nName: %(name)s\nUser: %(user)s\n-----------' % dbi)
    add_default_libelle()
    add_default_rights()
    add_default_interfaces()
    add_default_counter()
    print("End initialize data")


@app.cli.command("fix")
def fix_datas():
    from common.fix import apply
    print("Starting applying fixes")
    apply()
    print("Done applying fixes")


@app.cli.command('fix-patients')
def fix_patients():
    from common.fix import check_episodes_from_patients
    print('Starting fixing patients')
    check_episodes_from_patients()
    print('Fixing patients done')


@app.cli.command("riedl")
def riedl_management():
    from common.database import median_information
    from common.migration import riedl_migration
    dbi = median_information()
    print('Database information\nHost: %(server)s\nPort: %(port)s\nName: %(name)s\nUser: %(user)s\n-----------' % dbi)
    riedl_migration()
    print("End of Riedl migration")


@app.cli.command("cleanup")
def cleanup():
    from common.cleanup import clean_inventory
    print("Start Cleanup")
    clean_inventory()
    print("Cleanup end")


@app.cli.command("report")
def command_report():
    from common.report import report_entry_point
    print("Start report at %s" % time.strftime("%Y-%m-%d %H:%M:%S"))
    report_entry_point()
    print("End report at %s" % time.strftime("%Y-%m-%d %H:%M:%S"))


@app.cli.command("translation")
@click.option('--resource', is_flag=True, help="Generate resource files from translation files")
@click.option('--json', is_flag=True, help="Generate translation files from resource files")
@click.option('--language',  help="Generate translation files from resource files")
def translationPo(resource=False, json=False, language=None):
    if resource:
        print("Generate resource files")
        generate_resources_files()
    if json:
        print("Generate translation files")
        generate_translations_files()
    if language is not None:
        generate_translations_lang(language)


@app.cli.command("demo")
@click.option('--force', is_flag=True, help="Force is mandatory to generate demo data")
@click.option('--clean', is_flag=True, help="Clean all riedl demo data")
@click.option('--riedl', is_flag=True, help="Generate RIEDL demo data")
@click.option('--acced', is_flag=True, help="Generate ACCED demo data")
@click.option('--astus', is_flag=True, help="Generate ASTUS demo data")
@click.option('--external', is_flag=True, help="Generate EXTERNAL demo data")
def demo_generator(force=False, clean=False, riedl=False, acced=False, astus=False, external=False):
    from common.demo import demo_riedl, demo_acced_globale, demo_acced_nominatif, \
        demo_riedl_storage, demo_riedl_taking_mode, demo_astus_nominatif, demo_external_unload

    if clean and riedl:
        demo_riedl(clean)
        demo_riedl_storage(clean)
        demo_riedl_taking_mode(clean)
    elif clean and acced:
        demo_acced_globale(clean)
        demo_acced_nominatif(clean)
    elif clean and astus:
        demo_astus_nominatif(clean)
    elif clean and external:
        demo_external_unload(clean)

    if force and riedl:
        print("Generate demo data for RIEDL")
        demo_riedl()
        demo_riedl_storage()
        demo_riedl_taking_mode()
    elif force and acced:
        print("Generate demo data for ACCED")
        demo_acced_globale()
        demo_acced_nominatif()
    elif force and astus:
        print("Generate demo data for ASTUS")
        demo_astus_nominatif()
    elif force and external:
        print("Generate demo data for EXTERNAL")
        demo_external_unload()
    else:
        print("(!) Nothing append, use force Luck (!)")


# @scheduler.task('cron', id='notifications', second='*/10')
# def notifications():
#     notification_search()
