#!/usr/bin/env python3

import argparse
import json
import os
import sys

from pymongo import MongoClient


def _make_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('--host', help="Hostname or ip for the mongo database",
                        **environ_or_required('MONGO_HOST'))
    parser.add_argument('--port', help="Port for the mongo database",
                        **environ_or_required('MONGO_PORT'))
    
    parser.add_argument('--db-name', help="Name for the database used to insert", default="snapd")
    parser.add_argument('--db-collection', help="Name for the collection used to insert", default="spread_errors")
    parser.add_argument('--after-date', help="Find results after a date (yyyy-mm-dd)", default="2000-01-01")
    parser.add_argument('--after-time', help="Find results after a time (hh:mm:ss)", default="00:00:00")
    parser.add_argument('--before-date', help="Find results before a date (yyyy-mm-dd)", default="2999-12-12")
    parser.add_argument('--before-time', help="Find results before a time (hh:mm:ss)", default="24:00:00")
    parser.add_argument('--system', help="Find results for a specific spread system", default=".*")
    parser.add_argument('--backend', help="Find results for a specific spread backend", default=".*")
    parser.add_argument('--task', help="Find results for a specific spread task (include variant)", default=".*")
    parser.add_argument('--type', help="Find results for a specific type (Error or Debug)")
    parser.add_argument('--phase', help="Find results for a specific phase (preparing, executing, debbugging or restoring)")
    parser.add_argument('--text', help="Text to searh in the details")
    parser.add_argument('--exclude-detail', help="Exclude the error/debug details from the results", action='store_true')
    parser.add_argument('--limit', help="Number of values included in the output. By default the latest 1000 elements are retrieved", default=1000)

    return parser


def environ_or_required(key):
    if os.environ.get(key):
        return {'default': os.environ.get(key)}
    else:
        return {'required': True}


def connect(host, port, db_name):
    client = MongoClient(host=host, port=int(port))
    if not db_name in client.list_database_names():
        print("report-mongodb: invalid db name, it does not exist in mongodb")
        sys.exit(1)
    return client[db_name]


def _get_json(value):
    try:
        return json.loads(value)
    except ValueError as e:
        return None


def find(db, col, after_date, after_time, before_date, before_time, system, backend, task, type, phase, text, exclude_detail, limit):
    if not col in db.list_collection_names():
        print("report-mongodb: invalid db collection, it does not exist in db")
        sys.exit(1)

    # Filter the results based on some useful filters
    filter = {}
    filter["date"] = {'$gt': after_date, '$lt': before_date}
    filter["time"] = {'$gt': after_time, '$lt': before_time}
    task_exp = '{}:{}:.*/{}'.format(backend, system, task)
    filter["task"] = {'$regex': task_exp}
    if type:
        filter["info_type"] = type.capitalize()
    if phase:
        filter["verb"] = phase.lower()
    if text:
        filter["detail.lines"] = {'$regex': text}

    # Which fields have to be included and excluded
    project = {}
    if exclude_detail:
        project['detail'] = 0
    project['_id'] = 0

    # Sort by date and time
    sort = [('date', -1),('time', -1)]

    elems = db[col].find(filter, project).limit(int(limit)).sort(sort)
    for elem in elems:
        print(elem)

def main():
    parser = _make_parser()
    args = parser.parse_args()

    if not args.host or not args.port:
        print("report-mongodb: host or port not specified")
        sys.exit(1)

    if not args.db_name or not args.db_collection:
        print("report-mongodb: db name or db collection not specified")
        sys.exit(1)

    db = connect(args.host, args.port, args.db_name)
    find(
        db,
        args.db_collection,
        args.after_date, 
        args.after_time, 
        args.before_date, 
        args.before_time, 
        args.system, 
        args.backend, 
        args.task,
        args.type,
        args.phase,
        args.text,
        args.exclude_detail,
        args.limit)


if __name__ == "__main__":
    main()
