#!/usr/bin/env python3

import anki_vector
from time import sleep
from os.path import join
from os import remove
from flask import render_template, url_for, redirect, flash, request, Blueprint
from flask_login import current_user
from vectorcloud.main.forms import CommandForm, SearchForm, PromptForm
from vectorcloud.application_system.forms import UploadScript, AppSettings
from vectorcloud.application_system.utils import set_db_settings, save_icon,\
    save_script_helpers
from vectorcloud.models import Command, User, Status, Application, Output,\
    ApplicationStore, Settings, AppSupport, AppPrompt
from vectorcloud.main.utils import execute_db_commands, get_stats,\
    undock_robot, dock_robot, robot_connect_cube, server_reboot_func,\
    server_shutdown_func
from vectorcloud.application_store.utils import clear_temp_folder
from vectorcloud.paths import lib_folder, root_folder
from vectorcloud.errors import errors
from vectorcloud import db, app


main = Blueprint('main', __name__)


# ------------------------------------------------------------------------------
# intial routes and functions (before/after request)
# ------------------------------------------------------------------------------

# get the operating system & SDK version
vectorcloud_sdk_version = "0.6.0"
sdk_version = anki_vector.__version__

# create all tables in the database if they don't exist
db.create_all()


# blocks access to all pages (except public routes) unless the user is
# signed in.
@main.before_request
def check_valid_login():
    user = db.session.query(User).first()

    if any([request.endpoint.startswith('static'),
            current_user.is_authenticated,
            getattr(app.view_functions[request.endpoint],
                    'is_public', False)]):
        return

    elif user is None:
        return redirect(url_for('user_system.register'))

    else:
        return redirect(url_for('user_system.login'))


# this was a fix to make sure images stored in the cache are deleted when
# a new image is uploaded
@main.after_request
def add_header(response):
    if 'Cache-Control' not in response.headers:
        response.headers['Cache-Control'] = 'no-store'
    clear_temp_folder()
    return response


# ------------------------------------------------------------------------------
# Home routes
# ------------------------------------------------------------------------------

# Home page
@main.route("/")
@main.route("/home", methods=['GET', 'POST'])
def home():
    prompt = AppPrompt.query.first()
    if prompt:
        if prompt.question:
            return redirect(url_for('main.prompt'))

    settings = Settings.query.first()
    search_term = None
    num_results = 0

    if sdk_version != vectorcloud_sdk_version:
        flash('You are using a different version of the SDK than VectorCloud!\
               You are using ' + sdk_version + ' VectorCloud is using ' +
              vectorcloud_sdk_version, 'warning')

    output = Output.query.all()
    for out in output:
        flash(out, 'success')
    db.session.query(Output).delete()
    db.session.commit()

    app_list = Application.query.all()
    store_app_list = ApplicationStore.query.all()

    for store_app in store_app_list:
        for main_app in app_list:
            if store_app.script_name.lower() == main_app.script_name.lower():
                store_app.installed = True
                db.session.merge(store_app)
                db.session.commit()
            else:
                store_app.installed = False

    app_support = AppSupport.query.all()

    for main_app in app_list:
        for settings_file in app_support:
            if main_app.hex_id in settings_file.file_name:
                set_db_settings(main_app.hex_id, settings_file)

    form = CommandForm()
    search_form = SearchForm()
    edit_form = UploadScript()
    settings_form = AppSettings()

    if request.method == 'POST':
        form_name = request.form['form-name']

        if form_name == 'command-form':
            robot_command = Command(command=form.command.data)
            db.session.add(robot_command)
            db.session.commit()
            return redirect(url_for('main.home'))

        elif form_name == 'search-form':
            settings.search_by_name = search_form.by_name.data
            settings.search_by_description = search_form.by_description.data
            settings.search_by_author = search_form.by_author.data
            db.session.merge(settings)
            db.session.commit()
            search_term = search_form.search.data
            apps_searched = []

            if search_form.by_name.data is True:
                for application in app_list:
                    if search_term.lower() in application.script_name.lower():
                        apps_searched.append(application.script_name)

            if search_form.by_description.data is True:
                for application in app_list:
                    if search_term.lower() in application.description.lower():
                        apps_searched.append(application.script_name)

            if search_form.by_author.data is True:
                for application in app_list:
                    if search_term.lower() in application.author.lower():
                        apps_searched.append(application.script_name)

            app_list = Application.query\
                .filter(Application.script_name.in_(apps_searched))
            apps_searched = set(apps_searched)
            num_results = len(apps_searched)

        elif form_name == 'settings-form':
            hex_id = settings_form.hex_id.data
            settings_file_fn = join(lib_folder, hex_id + '.ini')
            settings_file = open(settings_file_fn, "w")
            settings_file.write(settings_form.variable.data)
            settings_file.close()
            flash('Settings saved!', 'success')
            return redirect(url_for('main.home'))

        elif form_name == 'edit-form':
            script_hex_id = edit_form.hex_id.data
            application = Application.query.filter_by(
                hex_id=script_hex_id).first()

            application.run_in_bkrd = edit_form.run_in_bkrd.data
            application.script_name = edit_form.script_name.data
            application.author = edit_form.author.data
            application.website = edit_form.website.data
            application.description = edit_form.description.data
            db.session.merge(application)
            db.session.commit()
            flash('Application Edited!', 'success')
            return redirect(url_for('main.home'))

        elif form_name == 'files-form':
            script_hex_id = edit_form.hex_id.data
            application = Application.query.filter_by(
                hex_id=script_hex_id).first()

            if edit_form.script.data:
                scriptn = script_hex_id + '.py'
                script_path = join(root_folder, scriptn)
                remove(script_path)
                edit_form.script.data.save(script_path)

            if edit_form.icon.data:
                if application.icon != 'default.png':
                    icon_path = join(app.root_path,
                                     'static/app_icons',
                                     application.icon)
                    remove(icon_path)

                icon_fn = save_icon(edit_form.icon.data, script_hex_id)
                application.icon = icon_fn

            if edit_form.script_helpers.data:
                for helper in edit_form.script_helpers.data:
                    is_in_db = save_script_helpers(helper, script_hex_id)
                    if is_in_db is True:
                        flash("Helper File Already in Lib!", 'warning')
                        return redirect(url_for('main.home'))

            flash('Files Edited!', 'success')

    elif request.method == 'GET':
        search_form.by_name.data = settings.search_by_name
        search_form.by_description.data = settings.search_by_description
        search_form.by_author.data = settings.search_by_author

    command_list = Command.query.all()

    err_msg = get_stats()
    if err_msg:
        flash('No Vector is Connected. Error message: ' + err_msg, 'warning')

    vector_status = Status.query.first()
    support_files = AppSupport.query.all()

    return render_template('home.html',
                           vector_status=vector_status,
                           form=form, command_list=command_list,
                           app_list=app_list,
                           sdk_version=sdk_version,
                           search_form=search_form,
                           search_term=search_term,
                           num_results=num_results,
                           edit_form=edit_form,
                           support_files=support_files,
                           settings_form=settings_form)


# executes all commmands in the command table(if present), redirects to home.
@main.route("/execute_commands", methods=['GET', 'POST'])
def execute_commands():
    func_out = execute_db_commands()

    if func_out in errors:
        flash('SDK Error. Message: ' + func_out, 'warning')

    return redirect(url_for('main.home'))


# clears the command table, redirects to home.
@main.route("/clear_commands")
def clear_commands():
    db.session.query(Command).delete()
    db.session.commit()
    return redirect(url_for('main.home'))


# adds undock command to the command table, runs robot_do(), redirects to home.
@main.route("/undock")
def undock():
    undock_robot()
    return redirect(url_for('main.home'))


# adds dock command to the command table, runs robot_do(), redirects to home.
@main.route("/dock")
def dock():
    dock_robot()
    return redirect(url_for('main.home'))


# connects to cube to get data
@main.route("/connect_cube")
def connect_cube():
    robot_connect_cube()
    return redirect(url_for('main.home'))


@main.route("/prompt", methods=['GET', 'POST'])
def prompt():
    err_msg = get_stats()
    if err_msg:
        flash('No Vector is Connected. Error message: ' + err_msg, 'warning')

    form = PromptForm()

    vector_status = Status.query.first()

    prompt = AppPrompt.query.first()

    if prompt:
        if form.validate_on_submit():
            prompt.answer = form.answer.data
            db.session.merge(prompt)
            db.session.commit()
            form.answer.data = None
            while True:
                db.session.expire_all()
                prompt = AppPrompt.query.first()
                if prompt.output:
                    flash(prompt.output, 'success')
                    prompt.output = None
                    db.session.merge(prompt)
                    db.session.commit()
                    break
                else:
                    pass

    else:
        return redirect(url_for('main.home'))

    return render_template('prompt.html',
                           vector_status=vector_status,
                           sdk_version=sdk_version,
                           form=form,
                           prompt=prompt)


@main.route("/cancel_prompt")
def cancel_prompt():
    db.session.query(AppPrompt).delete()
    db.session.commit()
    sleep(1)
    return redirect(url_for('main.home'))


@main.route("/server_shutdown")
def server_shutdown():
    server_shutdown_func()
    return redirect(url_for('main.home'))


@main.route("/server_reboot")
def server_reboot():
    server_reboot_func()
    return redirect(url_for('main.home'))