import logging

from flask import Blueprint, request
import elasticsearch.exceptions as elk_ex
from werkzeug import exceptions as wz_exceptions
from pillar.api.utils import authorization, jsonify

from . import queries

log = logging.getLogger(__name__)

blueprint_search = Blueprint('elksearch', __name__)

TERMS = [
    'node_type', 'media',
    'tags', 'is_free', 'projectname',
    'roles',
]


def _term_filters(args) -> dict:
    """
    Check if frontent wants to filter stuff
    on specific fields AKA facets

    return mapping with term field name
    and provided user term value
    """
    return {term: args.get(term, '') for term in TERMS}


def _page_index(page) -> int:
    """Return the page index from the query string."""
    try:
        page_idx = int(page)
    except TypeError:
        log.info('invalid page number %r received', request.args.get('page'))
        raise wz_exceptions.BadRequest()
    return page_idx


@blueprint_search.route('/', methods=['GET'])
def search_nodes():
    searchword = request.args.get('q', '')
    project_id = request.args.get('project', '')
    terms = _term_filters(request.args)
    page_idx = _page_index(request.args.get('page', 0))

    result = queries.do_node_search(searchword, terms, page_idx, project_id)
    return jsonify(result)

@blueprint_search.route('/multisearch', methods=['POST'])
def multi_search_nodes():
    if len(request.args) != 1:
        log.info(f'Expected 1 argument, received {len(request.args)}')

    json_obj = request.json
    q = []
    for row in json_obj:
        q.append({
            'query': row.get('q', ''),
            'project_id': row.get('project', ''),
            'terms': _term_filters(row),
            'page': _page_index(row.get('page', 0))
        })

    result = queries.do_multi_node_search(q)
    return jsonify(result)

@blueprint_search.route('/user')
def search_user():
    searchword = request.args.get('q', '')
    terms = _term_filters(request.args)
    page_idx = _page_index(request.args.get('page', 0))
    # result is the raw elasticseach output.
    # we need to filter fields in case of user objects.

    try:
        result = queries.do_user_search(searchword, terms, page_idx)
    except elk_ex.ElasticsearchException as ex:
        resp = jsonify({'_message': str(ex)})
        resp.status_code = 500
        return resp

    return jsonify(result)


@blueprint_search.route('/admin/user')
@authorization.require_login(require_cap='admin')
def search_user_admin():
    """
    User search over all fields.
    """

    searchword = request.args.get('q', '')
    terms = _term_filters(request.args)
    page_idx = _page_index(_page_index(request.args.get('page', 0)))

    try:
        result = queries.do_user_search_admin(searchword, terms, page_idx)
    except elk_ex.ElasticsearchException as ex:
        resp = jsonify({'_message': str(ex)})
        resp.status_code = 500
        return resp

    return jsonify(result)
