from flask import (
    abort,
    current_app,
    render_template,
    send_from_directory
)
from flask_login import current_user, login_required
from threading import Thread
import os
from app import db
from app.decorators import admin_required
from app.models import Job, JobInput, JobResult, JobStatus
from . import bp


@bp.route('/<hashid:job_id>')
@login_required
def job(job_id):
    job = Job.query.get_or_404(job_id)
    if not (job.user == current_user or current_user.is_administrator()):
        abort(403)
    return render_template(
        'jobs/job.html.j2',
        job=job,
        title='Job'
    )


@bp.route('/<hashid:job_id>', methods=['DELETE'])
@login_required
def delete_job(job_id):
    def _delete_job(app, job_id):
        with app.app_context():
            job = Job.query.get(job_id)
            job.delete()
            db.session.commit()

    job = Job.query.get_or_404(job_id)
    if not (job.user == current_user or current_user.is_administrator()):
        abort(403)
    thread = Thread(
        target=_delete_job,
        args=(current_app._get_current_object(), job_id)
    )
    thread.start()
    return {}, 202


@bp.route('/<hashid:job_id>/log')
@login_required
@admin_required
def job_log(job_id):
    job = Job.query.get_or_404(job_id)
    if job.status not in [JobStatus.COMPLETED, JobStatus.FAILED]:
        response = {'errors': {'message': 'Job status is not completed or failed'}}
        return response, 409
    with open(os.path.join(job.path, 'pipeline_data', 'logs', 'pyflow_log.txt')) as log_file:
        log = log_file.read()
    return log, 200, {'Content-Type': 'text/plain; charset=utf-8'}


@bp.route('/<hashid:job_id>/restart', methods=['POST'])
@login_required
def restart_job(job_id):
    def _restart_job(app, job_id):
        with app.app_context():
            job = Job.query.get(job_id)
            job.restart()
            db.session.commit()

    job = Job.query.get_or_404(job_id)
    if not (job.user == current_user or current_user.is_administrator()):
        abort(403)
    if job.status == JobStatus.FAILED:
        response = {'errors': {'message': 'Job status is not "failed"'}}
        return response, 409
    thread = Thread(
        target=_restart_job,
        args=(current_app._get_current_object(), job_id)
    )
    thread.start()
    return {}, 202


@bp.route('/<hashid:job_id>/inputs/<hashid:job_input_id>/download')
@login_required
def download_job_input(job_id, job_input_id):
    job_input = JobInput.query.get_or_404(job_input_id)
    if job_input.job.id != job_id:
        abort(404)
    if not (job_input.job.user == current_user or current_user.is_administrator()):
        abort(403)
    return send_from_directory(
        os.path.dirname(job_input.path),
        os.path.basename(job_input.path),
        as_attachment=True,
        attachment_filename=job_input.filename,
        mimetype=job_input.mimetype
    )


@bp.route('/<hashid:job_id>/results/<hashid:job_result_id>/download')
@login_required
def download_job_result(job_id, job_result_id):
    job_result = JobResult.query.get_or_404(job_result_id)
    if job_result.job.id != job_id:
        abort(404)
    if not (job_result.job.user == current_user or current_user.is_administrator()):
        abort(403)
    return send_from_directory(
        os.path.dirname(job_result.path),
        os.path.basename(job_result.path),
        as_attachment=True,
        attachment_filename=job_result.filename,
        mimetype=job_result.mimetype
    )
