import os
import json
from flask import Flask, render_template, send_from_directory, request, \
    url_for, abort, g, redirect, jsonify, session, flash, Response
from flask_login import login_required
from fatcat_client import Editgroup
from fatcat_client.rest import ApiException
from fatcat_tools.transforms import *
from fatcat_web import app, api, auth_api, priv_api
from fatcat_web.auth import handle_token_login, handle_logout, load_user, handle_ia_xauth
from fatcat_web.cors import crossdomain
from fatcat_web.search import *
from fatcat_web.forms import *
### Helper Methods ##########################################################
def form_editgroup_get_or_create(api, edit_form):
    """
    This function expects a submitted, validated 
    """
    if edit_form.editgroup_id.data:
        try:
            eg = api.get_editgroup(edit_form.editgroup_id.data)
        except ApiException as ae:
            if ae.status == 404:
                edit_form.editgroup_id.errors.append("Editgroup does not exist")
                return None
            app.log.warn(ae)
            abort(ae.status)
        # TODO: check here that editgroup hasn't been merged already
    else:
        # if no editgroup, create one from description
        try:
            eg = api.create_editgroup(
                Editgroup(description=edit_form.editgroup_description.data or None))
        except ApiException as ae:
            app.log.warn(ae)
            abort(ae.status)
        # set this session editgroup_id
        session['active_editgroup_id'] = eg.editgroup_id
        flash('Started new editgroup {}' \
            .format(eg.editgroup_id, eg.editgroup_id))
    return eg
### Views ###################################################################
@app.route('/container/create', methods=['GET', 'POST'])
@login_required
def container_create():
    form = ContainerEntityForm()
    if form.is_submitted():
        if form.validate_on_submit():
            # API on behalf of user
            user_api = auth_api(session['api_token'])
            eg = form_editgroup_get_or_create(user_api, form)
            if eg:
                # no merge or anything hard to do; just create the entity
                entity = form.to_entity()
                try:
                    edit = user_api.create_container(entity, editgroup_id=eg.editgroup_id)
                except ApiException as ae:
                    app.log.warn(ae)
                    abort(ae.status)
                # redirect to new entity
                return redirect('/container/{}'.format(edit.ident))
        elif form.errors:
            app.log.info("form errors (did not validate): {}".format(form.errors))
    else:
        editgroup_id = session.get('active_editgroup_id', None)
        form.editgroup_id.data = editgroup_id
    return render_template('container_create.html', form=form)
@login_required
@app.route('/container//edit', methods=['GET', 'POST'])
def container_edit(ident):
    # TODO: prev_rev interlock
    try:
        entity = api.get_container(ident)
    except ApiException as ae:
        abort(ae.status)
    form = ContainerEntityForm()
    if form.is_submitted():
        if form.validate_on_submit():
            # API on behalf of user
            user_api = auth_api(session['api_token'])
            eg = form_editgroup_get_or_create(user_api, form)
            if eg:
                # all the tricky logic is in the update method
                form.update_entity(entity)
                try:
                    edit = user_api.update_container(entity.ident, entity,
                        editgroup_id=eg.editgroup_id)
                except ApiException as ae:
                    app.log.warn(ae)
                    abort(ae.status)
                # redirect to entity revision
                # TODO: container_rev_view
                return redirect('/container/{}'.format(edit.ident))
        elif form.errors:
            app.log.info("form errors (did not validate): {}".format(form.errors))
    else:
        form = ContainerEntityForm.from_entity(entity)
    if not form.is_submitted():
        editgroup_id = session.get('active_editgroup_id', None)
        form.editgroup_id.data = editgroup_id
    return render_template('container_edit.html', form=form, entity=entity)
@app.route('/creator//edit', methods=['GET'])
def creator_edit(ident):
    try:
        entity = api.get_creator(ident)
    except ApiException as ae:
        abort(ae.status)
    return render_template('entity_edit.html')
@app.route('/file/create', methods=['GET', 'POST'])
@login_required
def file_create():
    form = FileEntityForm()
    if form.is_submitted():
        if form.validate_on_submit():
            # API on behalf of user
            user_api = auth_api(session['api_token'])
            eg = form_editgroup_get_or_create(user_api, form)
            if eg:
                # no merge or anything hard to do; just create the entity
                entity = form.to_entity()
                try:
                    edit = user_api.create_file(entity, editgroup_id=eg.editgroup_id)
                except ApiException as ae:
                    app.log.warn(ae)
                    abort(ae.status)
                # redirect to new entity
                return redirect('/file/{}'.format(edit.ident))
        elif form.errors:
            app.log.info("form errors (did not validate): {}".format(form.errors))
    else:
        editgroup_id = session.get('active_editgroup_id', None)
        form.editgroup_id.data = editgroup_id
        form.urls.append_entry()
        form.release_ids.append_entry()
    return render_template('file_create.html',
        form=form)
@login_required
@app.route('/file//edit', methods=['GET', 'POST'])
def file_edit(ident):
    # TODO: prev_rev interlock
    try:
        entity = api.get_file(ident)
    except ApiException as ae:
        abort(ae.status)
    form = FileEntityForm()
    if form.is_submitted():
        if form.validate_on_submit():
            # API on behalf of user
            user_api = auth_api(session['api_token'])
            eg = form_editgroup_get_or_create(user_api, form)
            if eg:
                # all the tricky logic is in the update method
                form.update_entity(entity)
                try:
                    edit = user_api.update_file(entity.ident, entity,
                        editgroup_id=eg.editgroup_id)
                except ApiException as ae:
                    app.log.warn(ae)
                    abort(ae.status)
                # redirect to entity revision
                # TODO: file_rev_view
                return redirect('/file/{}'.format(edit.ident))
        elif form.errors:
            app.log.info("form errors (did not validate): {}".format(form.errors))
    else: # not submitted
        form = FileEntityForm.from_entity(entity)
        editgroup_id = session.get('active_editgroup_id', None)
        form.editgroup_id.data = editgroup_id
    return render_template('file_edit.html', form=form, entity=entity)
@app.route('/fileset//edit', methods=['GET'])
def fileset_edit(ident):
    try:
        entity = api.get_fileset(ident)
    except ApiException as ae:
        abort(ae.status)
    return render_template('entity_edit.html'), 404
@app.route('/webcapture//edit', methods=['GET'])
def webcapture_edit(ident):
    try:
        entity = api.get_webcapture(ident)
    except ApiException as ae:
        abort(ae.status)
    return render_template('entity_edit.html'), 404
@app.route('/release/create', methods=['GET', 'POST'])
@login_required
def release_create():
    form = ReleaseEntityForm()
    if form.is_submitted():
        if form.validate_on_submit():
            # API on behalf of user
            user_api = auth_api(session['api_token'])
            eg = form_editgroup_get_or_create(user_api, form)
            if eg:
                # no merge or anything hard to do; just create the entity
                entity = form.to_entity()
                try:
                    edit = user_api.create_release(entity, editgroup_id=eg.editgroup_id)
                except ApiException as ae:
                    app.log.warn(ae)
                    abort(ae.status)
                # redirect to new release
                return redirect('/release/{}'.format(edit.ident))
        elif form.errors:
            app.log.info("form errors (did not validate): {}".format(form.errors))
    else: # not submitted
        form.contribs.append_entry()
        editgroup_id = session.get('active_editgroup_id', None)
        form.editgroup_id.data = editgroup_id
    return render_template('release_create.html', form=form)
@login_required
@app.route('/release//edit', methods=['GET', 'POST'])
def release_edit(ident):
    # TODO: prev_rev interlock
    try:
        entity = api.get_release(ident)
    except ApiException as ae:
        abort(ae.status)
    form = ReleaseEntityForm()
    if form.is_submitted():
        if form.validate_on_submit():
            # API on behalf of user
            user_api = auth_api(session['api_token'])
            eg = form_editgroup_get_or_create(user_api, form)
            if eg:
                # all the tricky logic is in the update method
                form.update_entity(entity)
                try:
                    edit = user_api.update_release(entity.ident, entity,
                        editgroup_id=eg.editgroup_id)
                except ApiException as ae:
                    app.log.warn(ae)
                    abort(ae.status)
                # redirect to entity revision
                # TODO: release_rev_view
                return redirect('/release/{}'.format(edit.ident))
        elif form.errors:
            app.log.info("form errors (did not validate): {}".format(form.errors))
    else: # not submitted
        form = ReleaseEntityForm.from_entity(entity)
        editgroup_id = session.get('active_editgroup_id', None)
        form.editgroup_id.data = editgroup_id
    return render_template('release_edit.html', form=form, entity=entity)
@app.route('/work/create', methods=['GET'])
def work_create_view():
    return abort(404)
@app.route('/work//edit', methods=['GET'])
def work_edit_view(ident):
    try:
        entity = api.get_work(ident)
    except ApiException as ae:
        abort(ae.status)
    return render_template('entity_edit.html'), 404