from flask import session
import cqi
import json
import math
import os
from app import socketio
from app.decorators import socketio_login_required
from app.models import Corpus
from . import NAMESPACE as ns
from .utils import cqi_over_socketio, export_subcorpus


@socketio.on('cqi.corpora.corpus.subcorpora.get', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_get(cqi_client: cqi.CQiClient, corpus_name: str, subcorpus_name: str):  # noqa
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    cqi_subcorpus = cqi_corpus.subcorpora.get(subcorpus_name)
    payload = {**cqi_subcorpus.attrs}
    return {'code': 200, 'msg': 'OK', 'payload': payload}


@socketio.on('cqi.corpora.corpus.subcorpora.list', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_list(cqi_client: cqi.CQiClient, corpus_name: str):  # noqa
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    payload = [{**x.attrs} for x in cqi_corpus.subcorpora.list()]
    return {'code': 200, 'msg': 'OK', 'payload': payload}


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


@socketio.on('cqi.corpora.corpus.subcorpora.subcorpus.dump', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_subcorpus_dump(cqi_client: cqi.CQiClient):
    return {'code': 501, 'msg': 'Not Implemented'}


@socketio.on('cqi.corpora.corpus.subcorpora.subcorpus.fdist_1', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_subcorpus_fdist_1(cqi_client: cqi.CQiClient):
    return {'code': 501, 'msg': 'Not Implemented'}


@socketio.on('cqi.corpora.corpus.subcorpora.subcorpus.fdist_2', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_subcorpus_fdist_2(cqi_client: cqi.CQiClient):
    return {'code': 501, 'msg': 'Not Implemented'}


###############################################################################
# nopaque specific CQi extensions                                             #
###############################################################################
@socketio.on('cqi.corpora.corpus.subcorpora.subcorpus.paginate', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_subcorpus_paginate(cqi_client: cqi.CQiClient, corpus_name: str, subcorpus_name: str, context: int = 50, page: int = 1, per_page: int = 20):  # noqa
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    cqi_subcorpus = cqi_corpus.subcorpora.get(subcorpus_name)
    # Sanity checks
    if (
        per_page < 1
        or page < 1
        or (
            cqi_subcorpus.attrs['size'] > 0
            and page > math.ceil(cqi_subcorpus.attrs['size'] / per_page)
        )
    ):
        return {'code': 416, 'msg': 'Range Not Satisfiable'}
    offset = (page - 1) * per_page
    cutoff = per_page
    cqi_results_export = export_subcorpus(
        cqi_subcorpus, context=context, cutoff=cutoff, offset=offset)
    payload = {}
    # the items for the current page
    payload['items'] = cqi_results_export.pop('matches')
    # the lookups for the items
    payload['lookups'] = cqi_results_export
    # the total number of items matching the query
    payload['total'] = cqi_subcorpus.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}


@socketio.on('cqi.corpora.corpus.subcorpora.subcorpus.export', namespace=ns)
@socketio_login_required
@cqi_over_socketio
def cqi_corpora_corpus_subcorpora_subcorpus_export(cqi_client: cqi.CQiClient, corpus_name: str, subcorpus_name: str, context: int = 50):  # noqa
    cqi_corpus = cqi_client.corpora.get(corpus_name)
    cqi_subcorpus = cqi_corpus.subcorpora.get(subcorpus_name)
    cqi_subcorpus_export = export_subcorpus(cqi_subcorpus, context=context)
    corpus = Corpus.query.get(session['d']['corpus_id'])
    file_path = os.path.join(corpus.path, f'{subcorpus_name}.json')
    with open(file_path, 'w') as file:
        json.dump(cqi_subcorpus_export, file)
    return {'code': 200, 'msg': 'OK'}
