#!/usr/bin/env python
#
# This file is part of vospace-transfer-service
# Copyright (C) 2021 Istituto Nazionale di Astrofisica
# SPDX-License-Identifier: GPL-3.0-or-later
#

import json
import sys

from redis_rpc_client import RedisRPCClient
from config import Config
from tabulate import tabulate


class VOSJob(RedisRPCClient):

    def __init__(self):
        config = Config("/etc/vos_cli/vos_cli.conf")
        params = config.loadSection("server")
        self.host = params["host"]
        self.port = params.getint("port")
        self.db = params.getint("db")
        params = config.loadSection("vos_job")
        self.rpcQueue = params["rpc_queue"]
        self.jobPhases = ("pending", "queued", "executing", "completed", "error")
        super(VOSJob, self).__init__(self.host, self.port, self.db, self.rpcQueue)

    def listJobs(self, jobPhase = ""):
        if not jobPhase:
            jobRequest = { "requestType": "JOB_LIST" }
        else:
            jobPhase = jobPhase.upper()
            jobRequest = { "requestType": "JOB_BY_PHASE", "jobPhase": jobPhase }
        jobResponse = self.call(jobRequest)
        if "responseType" not in jobResponse:
            sys.exit("FATAL: Malformed response.\n")
        elif jobResponse["responseType"] == "LST_DONE":
            jobList = jobResponse["jobList"]
            if jobList:
                print("\n" + tabulate(jobResponse["jobList"], headers = "keys", tablefmt = "pretty") + "\n")
            else:
                sys.exit("\nNo active jobs found.\n")
        elif jobResponse["responseType"] == "LST_BY_PHASE_DONE":
            jobList = jobResponse["jobList"]
            if jobList:
                print("\n" + tabulate(jobResponse["jobList"], headers = "keys", tablefmt = "pretty") + "\n")
            else:
                sys.exit(f"\nNo {jobPhase} jobs found.\n")
        elif jobResponse["responseType"] == "ERROR":
            errorCode = jobResponse["errorCode"]
            errorMsg = jobResponse["errorMsg"]
            sys.exit(f"\nError code: {errorCode}\nError message: {errorMsg}\n")
        else:
            sys.exit("\nFATAL: Unknown response type.\n")

    def info(self, jobId):
        jobRequest = { "requestType": "JOB_INFO", "jobId": jobId }
        jobResponse = self.call(jobRequest)
        if "responseType" not in jobResponse:
            sys.exit("FATAL: Malformed response.\n")
        elif jobResponse["responseType"] == "LST_INFO_DONE":
            jobInfo = jobResponse["jobInfo"]
            if jobInfo:
                print("\n" + json.dumps(jobInfo, indent = 4, sort_keys = True) + "\n")
            else:
                sys.exit(f"\nThere is no job with ID {jobId}\n")
        elif jobResponse["responseType"] == "ERROR":
            errorCode = jobResponse["errorCode"]
            errorMsg = jobResponse["errorMsg"]
            sys.exit(f"\nError code: {errorCode}\nError message: {errorMsg}\n")
        else:
            sys.exit("\nFATAL: Unknown response type.\n")
            
    def search(self, searchStr):
        jobRequest = { "requestType": "JOB_SEARCH", "searchStr": searchStr }
        jobResponse = self.call(jobRequest)
        if "responseType" not in jobResponse:
            sys.exit("FATAL: Malformed response.\n")
        elif jobResponse["responseType"] == "SEARCH_DONE":
            jobSearch = jobResponse["jobSearch"]
            if jobSearch:
                print("\n" + tabulate(jobResponse["jobSearch"], headers = "keys", tablefmt = "pretty") + "\n")
            else:
                sys.exit(f"\nThe search did not return any results.\n")
        elif jobResponse["responseType"] == "ERROR":
            errorCode = jobResponse["errorCode"]
            errorMsg = jobResponse["errorMsg"]
            sys.exit(f"\nError code: {errorCode}\nError message: {errorMsg}\n")
        else:
            sys.exit("\nFATAL: Unknown response type.\n")

    def results(self, jobId):
        jobRequest = { "requestType": "JOB_RESULTS", "jobId": jobId }
        jobResponse = self.call(jobRequest)
        if "responseType" not in jobResponse:
            sys.exit("FATAL: Malformed response.\n")
        elif jobResponse["responseType"] == "LST_RESULTS_DONE":
            jobResults = jobResponse["jobResults"]
            if jobResults:
                print("\n" + json.dumps(jobResults, indent = 4, sort_keys = True) + "\n")
            else:
                sys.exit(f"\nThere may be no job with ID {jobId} or it may still be active.\n")
        elif jobResponse["responseType"] == "ERROR":
            errorCode = jobResponse["errorCode"]
            errorMsg = jobResponse["errorMsg"]
            sys.exit(f"\nError code: {errorCode}\nError message: {errorMsg}\n")
        else:
            sys.exit("\nFATAL: Unknown response type.\n")

    def help(self):
        sys.exit("""
NAME
    vos_job

SYNOPSYS
    vos_job COMMAND [ARGUMENT]

DESCRIPTION
    Client tool to obtain information about jobs.

    The client accepts the following commands:

    list
        if launched without any argument it will display all the currently active jobs.
        The command can also be used with one argument, the job phase. The following 
        values are allowed:
        - pending
        - queued
        - executing
        - completed
        - error

    info
        prints a JSON object containing the job info according to the UWS specification.
        A job ID is required as argument
        
    search
        performs a search on jobs and returns those having a match between the search string
        passed by the user and one of the following fields: 
        
        'job_id', 'job_type', 'ownder_id', 'user_name'

    results
        prints a JSON object containing the job results according to the UWS specification.
        A job ID is required as argument.
        """)

# Create new VOSJob object
vosJobCli = VOSJob()

# Check the number of input args
if len(sys.argv) == 2:
    script, cmd = sys.argv
    if cmd == "list":
        vosJobCli.listJobs()
    else:
        vosJobCli.help()
elif len(sys.argv) == 3:
    script, cmd, arg = sys.argv
    if cmd == "list":
        if arg in vosJobCli.jobPhases:
            vosJobCli.listJobs(arg)
        else:
            vosJobCli.help()
    elif cmd == "info":
        vosJobCli.info(arg)
    elif cmd == "search":
        vosJobCli.search(arg)
    elif cmd == "results":
        vosJobCli.results(arg)
    else:
        vosJobCli.help()
else:
    vosJobCli.help()
