from flask import session
import cqi
import math
from app import db, socketio
from app.decorators import socketio_login_required
from app.models import Corpus
from . import NAMESPACE as ns
from .utils import cqi_over_socketio, lookups_by_cpos


@socketio.on('cqi.corpora.corpus.drop', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_drop(cqi_client: cqi.CQiClient, corpus_name: str):
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    cqi_status = cqi_corpus.drop()
    payload = {'code': cqi_status,
               'msg': cqi.api.specification.lookup[cqi_status]}
    return {'code': 200, 'msg': 'OK', 'payload': payload}


@socketio.on('cqi.corpora.corpus.query', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_query(cqi_client: cqi.CQiClient, corpus_name: str, subcorpus_name: str, query: str):  # noqa
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    cqi_status = cqi_corpus.query(subcorpus_name, query)
    payload = {'code': cqi_status,
               'msg': cqi.api.specification.lookup[cqi_status]}
    return {'code': 200, 'msg': 'OK', 'payload': payload}


###############################################################################
# nopaque specific CQi extensions                                             #
###############################################################################
@socketio.on('cqi.corpora.corpus.update_db', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_update_db(cqi_client: cqi.CQiClient, corpus_name: str):
    corpus = Corpus.query.get(session['d']['corpus_id'])
    corpus.num_tokens = cqi_client.corpora.get('CORPUS').attrs['size']
    db.session.commit()


@socketio.on('cqi.corpora.corpus.paginate', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_paginate(cqi_client: cqi.CQiClient, corpus_name: str, page: int = 1, per_page: int = 20):  # noqa
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    # Sanity checks
    if (
        per_page < 1
        or page < 1
        or (
            cqi_corpus.attrs['size'] > 0
            and page > math.ceil(cqi_corpus.attrs['size'] / per_page)
        )
    ):
        return {'code': 416, 'msg': 'Range Not Satisfiable'}
    first_cpos = (page - 1) * per_page
    last_cpos = min(cqi_corpus.attrs['size'], first_cpos + per_page)
    cpos_list = [*range(first_cpos, last_cpos)]
    lookups = lookups_by_cpos(cqi_corpus, cpos_list)
    payload = {}
    # the items for the current page
    payload['items'] = [cpos_list]
    # the lookups for the items
    payload['lookups'] = lookups
    # the total number of items matching the query
    payload['total'] = cqi_corpus.attrs['size']
    # the number of items to be displayed on a page.
    payload['per_page'] = per_page
    # The total number of pages
    payload['pages'] = math.ceil(payload['total'] / payload['per_page'])
    # the current page number (1 indexed)
    payload['page'] = page if payload['pages'] > 0 else None
    # True if a previous page exists
    payload['has_prev'] = payload['page'] > 1 if payload['page'] else False
    # True if a next page exists.
    payload['has_next'] = payload['page'] < payload['pages'] if payload['page'] else False  # noqa
    # Number of the previous page.
    payload['prev_num'] = payload['page'] - 1 if payload['has_prev'] else None
    # Number of the next page
    payload['next_num'] = payload['page'] + 1 if payload['has_next'] else None
    return {'code': 200, 'msg': 'OK', 'payload': payload}
