from app import db, hashids
from app.models import (
    Job,
    JobInput,
    JobStatus,
    TesseractOCRModel,
    TRANSKRIBUS_HTR_MODELS,
    TranskribusHTRModel
)
from flask import (
    abort,
    current_app,
    flash,
    make_response,
    render_template,
    request,
    url_for
)
from flask_login import current_user, login_required
from werkzeug.utils import secure_filename
from . import bp
from . import SERVICES
from .forms import (
    AddFileSetupPipelineJobForm,
    AddTesseractOCRPipelineJobForm,
    AddTranskribusHTRPipelineJobForm,
    AddSpacyNLPPipelineJobForm
)
import json


@bp.route('/file-setup-pipeline', methods=['GET', 'POST'])
@login_required
def file_setup_pipeline():
    service = 'file-setup-pipeline'
    service_manifest = SERVICES[service]
    version = request.args.get('version', service_manifest['latest_version'])
    if version not in service_manifest['versions']:
        abort(404)
    form = AddFileSetupPipelineJobForm(prefix='add-job-form', version=version)
    if form.is_submitted():
        if not form.validate():
            return make_response(form.errors, 400)
        service_args = {}
        job = Job(
            user=current_user,
            description=form.description.data,
            service=service,
            service_args=service_args,
            service_version=form.version.data,
            title=form.title.data
        )
        db.session.add(job)
        db.session.flush(objects=[job])
        db.session.refresh(job)
        try:
            job.makedirs()
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        for image_file in form.images.data:
            job_input = JobInput(
                filename=secure_filename(image_file.filename),
                job=job,
                mimetype=image_file.mimetype
            )
            db.session.add(job_input)
            db.session.flush(objects=[job_input])
            db.session.refresh(job_input)
            try:
                image_file.save(job_input.path)
            except OSError as e:
                current_app.logger.error(e)
                db.session.rollback()
                flash('Internal Server Error', 'error')
                return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job.status = JobStatus.SUBMITTED
        db.session.commit()
        flash(f'Job "{job.title}" added', 'job')
        return make_response({'redirect_url': url_for('jobs.job', job_id=job.id)}, 201)  # noqa
    return render_template(
        'services/file_setup_pipeline.html.j2',
        form=form,
        title=service_manifest['name']
    )


@bp.route('/tesseract-ocr-pipeline', methods=['GET', 'POST'])
@login_required
def tesseract_ocr_pipeline():
    service = 'tesseract-ocr-pipeline'
    service_manifest = SERVICES[service]
    version = request.args.get('version', service_manifest['latest_version'])
    if version not in service_manifest['versions']:
        abort(404)
    form = AddTesseractOCRPipelineJobForm(prefix='add-job-form', version=version)
    if form.is_submitted():
        if not form.validate():
            return make_response(form.errors, 400)
        service_args = {}
        service_args['model'] = hashids.decode(form.model.data)
        if form.binarization.data:
            service_args['binarization'] = True
        job = Job(
            user=current_user,
            description=form.description.data,
            service=service,
            service_args=service_args,
            service_version=form.version.data,
            title=form.title.data
        )
        db.session.add(job)
        db.session.flush(objects=[job])
        db.session.refresh(job)
        try:
            job.makedirs()
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job_input = JobInput(
            filename=secure_filename(form.pdf.data.filename),
            job=job,
            mimetype=form.pdf.data.mimetype
        )
        db.session.add(job_input)
        db.session.flush(objects=[job_input])
        db.session.refresh(job_input)
        try:
            form.pdf.data.save(job_input.path)
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job.status = JobStatus.SUBMITTED
        db.session.commit()
        flash(f'Job "{job.title}" added', 'job')
        return make_response({'redirect_url': url_for('jobs.job', job_id=job.id)}, 201)  # noqa
    tesseract_ocr_models = [
        x for x in TesseractOCRModel.query.filter().all()
        if version in x.compatible_service_versions and (x.shared == True or x.user == current_user)
    ]
    current_app.logger.warning(tesseract_ocr_models)
    return render_template(
        'services/tesseract_ocr_pipeline.html.j2',
        form=form,
        tesseract_ocr_models=tesseract_ocr_models,
        title=service_manifest['name']
    )


@bp.route('/transkribus-htr-pipeline', methods=['GET', 'POST'])
@login_required
def transkribus_htr_pipeline():
    if not current_app.config.get('NOPAQUE_TRANSKRIBUS_ENABLED'):
        abort(404)
    service = 'transkribus-htr-pipeline'
    service_manifest = SERVICES[service]
    version = request.args.get('version', service_manifest['latest_version'])
    if version not in service_manifest['versions']:
        abort(404)
    form = AddTranskribusHTRPipelineJobForm(prefix='add-job-form', version=version)
    if form.is_submitted():
        if not form.validate():
            return make_response(form.errors, 400)
        service_args = {}
        service_args['model'] = hashids.decode(form.model.data)
        if form.binarization.data:
            service_args['binarization'] = True
        job = Job(
            user=current_user,
            description=form.description.data,
            service=service,
            service_args=service_args,
            service_version=form.version.data,
            title=form.title.data
        )
        db.session.add(job)
        db.session.flush(objects=[job])
        db.session.refresh(job)
        try:
            job.makedirs()
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job_input = JobInput(
            filename=secure_filename(form.pdf.data.filename),
            job=job,
            mimetype=form.pdf.data.mimetype
        )
        db.session.add(job_input)
        db.session.flush(objects=[job_input])
        db.session.refresh(job_input)
        try:
            form.pdf.data.save(job_input.path)
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job.status = JobStatus.SUBMITTED
        db.session.commit()
        flash(f'Job "{job.title}" added', 'job')
        return make_response({'redirect_url': url_for('jobs.job', job_id=job.id)}, 201)  # noqa
    transkribus_htr_models = [
        x for x in TranskribusHTRModel.query.filter().all()
        if version in x.compatible_service_versions and (x.shared == True or x.user == current_user)
    ]
    return render_template(
        f'services/transkribus_htr_pipeline.html.j2',
        form=form,
        title=service_manifest['name'],
        TRANSKRIBUS_HTR_MODELS=TRANSKRIBUS_HTR_MODELS,
        transkribus_htr_models=transkribus_htr_models
    )


@bp.route('/spacy-nlp-pipeline', methods=['GET', 'POST'])
@login_required
def spacy_nlp_pipeline():
    service = 'spacy-nlp-pipeline'
    service_manifest = SERVICES[service]
    version = request.args.get('version', SERVICES[service]['latest_version'])
    if version not in service_manifest['versions']:
        abort(404)
    form = AddSpacyNLPPipelineJobForm(prefix='add-job-form', version=version)
    if form.is_submitted():
        if not form.validate():
            return make_response(form.errors, 400)
        service_args = {}
        service_args['model'] = form.model.data
        if form.encoding_detection.data:
            service_args['encoding_detection'] = True
        job = Job(
            user=current_user,
            description=form.description.data,
            service=service,
            service_args=service_args,
            service_version=form.version.data,
            title=form.title.data
        )
        db.session.add(job)
        db.session.flush(objects=[job])
        db.session.refresh(job)
        try:
            job.makedirs()
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job_input = JobInput(
            filename=secure_filename(form.txt.data.filename),
            job=job,
            mimetype=form.txt.data.mimetype
        )
        db.session.add(job_input)
        db.session.flush(objects=[job_input])
        db.session.refresh(job_input)
        try:
            form.txt.data.save(job_input.path)
        except OSError as e:
            current_app.logger.error(e)
            db.session.rollback()
            flash('Internal Server Error', 'error')
            return make_response({'redirect_url': url_for('.service', service=service)}, 500)  # noqa
        job.status = JobStatus.SUBMITTED
        db.session.commit()
        flash(f'Job "{job.title}" added', 'job')
        return make_response({'redirect_url': url_for('jobs.job', job_id=job.id)}, 201)  # noqa
    return render_template(
        'services/spacy_nlp_pipeline.html.j2',
        form=form,
        title=service_manifest['name']
    )


@bp.route('/corpus-analysis')
@login_required
def corpus_analysis():
    return render_template(
        'services/corpus_analysis.html.j2',
        title='Corpus analysis'
    )