from datetime import datetime
from flask import (
    abort,
    current_app,
    jsonify,
    request,
    url_for
)
from flask_login import current_user, login_required
from threading import Thread
from .decorators import corpus_follower_permission_required, corpus_owner_or_admin_required
from app import db, hashids
from app.decorators import content_negotiation
from app.models import Corpus, CorpusFollowerRole
from . import bp


@bp.route('/<hashid:corpus_id>', methods=['DELETE'])
@login_required
@corpus_owner_or_admin_required
@content_negotiation(produces='application/json')
def delete_corpus(corpus_id):
    def _delete_corpus(app, corpus_id):
        with app.app_context():
            corpus = Corpus.query.get(corpus_id)
            corpus.delete()
            db.session.commit()

    corpus = Corpus.query.get_or_404(corpus_id)
    thread = Thread(
        target=_delete_corpus,
        args=(current_app._get_current_object(), corpus.id)
    )
    thread.start()
    response_data = {
        'message': f'Corpus "{corpus.title}" marked for deletion',
        'category': 'corpus'
    }
    response = jsonify(response_data)
    response.status_code = 200
    return response


@bp.route('/<hashid:corpus_id>/build', methods=['POST'])
@login_required
@corpus_owner_or_admin_required
@content_negotiation(produces='application/json')
def build_corpus(corpus_id):
    def _build_corpus(app, corpus_id):
        with app.app_context():
            corpus = Corpus.query.get(corpus_id)
            corpus.build()
            db.session.commit()

    print(corpus_id)
    corpus = Corpus.query.get_or_404(corpus_id)
    if len(corpus.files.all()) == 0:
        abort(409)
    thread = Thread(
        target=_build_corpus,
        args=(current_app._get_current_object(), corpus_id)
    )
    thread.start()
    response_data = {
        'message': f'Corpus "{corpus.title}" marked for building',
        'category': 'corpus'
    }
    response = jsonify(response_data)
    response.status_code = 202
    return response


@bp.route('/<hashid:corpus_id>/generate-share-link', methods=['POST'])
@login_required
@corpus_follower_permission_required('GENERATE_SHARE_LINK')
@content_negotiation(consumes='application/json', produces='application/json')
def generate_corpus_share_link(corpus_id):
    corpus_hashid = hashids.encode(corpus_id)
    data = request.json
    if not isinstance(data, dict):
        abort(400)
    expiration = data.get('expiration')
    if not isinstance(expiration, str):
        abort(400)
    role_name = data.get('role')
    if not isinstance(role_name, str):
        abort(400)
    expiration_date = datetime.strptime(expiration, '%b %d, %Y')
    cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
    if cfr is None:
        abort(400)
    token = current_user.generate_follow_corpus_token(corpus_hashid, role_name, expiration_date)
    corpus_share_link = url_for(
        'corpora.follow_corpus',
        corpus_id=corpus_id,
        token=token,
        _external=True
    )
    response_data = {
        'message': 'Corpus share link generated',
        'category': 'corpus',
        'corpusShareLink': corpus_share_link
    }
    response = jsonify(response_data)
    response.status_code = 200
    return response
    


@bp.route('/<hashid:corpus_id>/is_public', methods=['PUT'])
@login_required
@corpus_owner_or_admin_required
@content_negotiation(consumes='application/json', produces='application/json')
def update_corpus_is_public(corpus_id):
    is_public = request.json
    if not isinstance(is_public, bool):
        abort(400)
    corpus = Corpus.query.get_or_404(corpus_id)
    corpus.is_public = is_public
    db.session.commit()
    response_data = {
        'message': (
            f'Corpus "{corpus.title}" is now'
            f' {"public" if is_public else "private"}'
        ),
        'category': 'corpus'
    }
    response = jsonify(response_data)
    response.status_code = 200
    return response
