import getopt, json, time
from metacat.webapi import MetaCatClient
from .ui_lib import pretty_json, parse_attrs, print_handles


create_project_help = """
create project [options] [inline MQL query]
        -q <file with MQL query>                    - read MQL query from file instead
        -c <name>[,<name>...]                       - copy metadata attributes from query results, use with -q or inline query

        -l (-|<file with file list>)                - read "namespace:name [attr=value ...]" lines from the file 
        -j (-|<file with file list>)                - read JSON file with file list {"namespace":...,"name"..., "attributes":{...}}

        -A @<file.json>                             - JSON file with project attributes
        -A "name=value name=value ..."              - project attributes
        -a @<file.json>                             - JSON file with common file attributes
        -a "name=value name=value ..."              - common file attributes

        -p (json|pprint|id)                         - print created project info as JSON, pprint or just project id (default)
"""


def create_project(client, rest):
    if not rest or "help" in rest:
        print(create_project_help)
        return
    opts, args = getopt.getopt(rest, "l:q:p:a:A:c:j:")
    opts = dict(opts)
    query = " ".join(args).strip()

    common_attrs = {}
    if "-a" in opts:
        attr_src = opts["-a"]
        if attr_src[0] == '@':
            common_attrs = json.load(open(attr_src[1:], "r"))
        else:
            common_attrs = parse_attrs(attr_src)
 
    project_attrs = {}
    if "-A" in opts:
        attr_src = opts["-A"]
        if attr_src[0] == '@':
            project_attrs = json.load(open(attr_src[1:], "r"))
        else:
            project_attrs = parse_attrs(attr_src)

    if not query and "-q" in opts:
            query = open(opts["-q"], "r").read().strip()
        
    if query:
        files = MetaCatClient().query(query, with_metadata = "-c" in opts)
        for info in files:
            info["attributes"] = common_attrs.copy()
        #
        # copy file attributes from metacat
        #
        
        if "-c" in opts:
            fields = opts["-c"].split(",")
            for info in files:
                #print(info["metadata"])
                attrs = {k:info["metadata"].get(k) for k in fields}
                info["attributes"].update(attrs)    
        
    elif "-j" in opts:
        inp = opts["-j"]
        if inp == "-":
            inp = sys.stdin
        else:
            inp = open(inp, "r")
        files = json.load(inp)
        if common_attrs:
            for info in files:
                attrs = info.get("attributes", {}).copy()
                attrs.update(common_attrs)
                info["attributes"] = attrs

    elif "-l" in opts:
        inp = opts["-l"]
        if inp == "-":
            inp = sys.stdin
        else:
            inp = open(inp, "r")
        files = []
        for line in inp:
            line = line.strip()
            if line:
                did, rest = (tuple(line.split(None, 1)) + (None,))[:2]
                namespace, name = did.split(":", 1)
                attrs = common_attrs.copy()
                if rest:
                    attrs.update(parse_attrs(rest))
                files.append({"namespace":namespace, "name":name, "attributes":attrs})

    #print("files:", files)
    info = client.create_project(files, attributes=project_attrs)
    printout = opts.get("-p", "id")
    if printout == "json":
        print(pretty_json(info))
    elif printout == "pprint":
        pprint.pprint(info)
    else:
        print(info["project_id"])

show_project_help = """
show project [options] <project_id>             - show project info (-j show as JSON)
    -a                                          - show project attributes only
    -r                                          - show replicas information
    -j                                          - show as JSON
    -f [active|ready|available|all|reserved|failed|done]    - list files (namespace:name) only
                                                   all       - all files, including done and failed
                                                   active    - all except done and failed
                                                   ready     - ready files only
                                                   available - available files only
                                                   reserved  - reserved files only
                                                   failed    - failed files only
                                                   done      - done files only
"""


def show_project(client, rest):
    if not rest or "help" in rest:
        print(show_project_help)
        return
    opts, args = getopt.getopt(rest, "jarf:")
    opts = dict(opts)
    project_id = args[0]
    info = client.get_project(project_id, with_files=True, with_replicas=True)
    if "-a" in opts:
        attrs = info.get("attributes", {})
        if "-j" in opts:
            print(pretty_json(attrs))
        else:
            for name, value in sorted(attrs.items()):
                print(f"{name} {value}")
    else:
        if "-j" in opts:
            print(pretty_json(info))
        elif "-f" in opts:
            filter_state = opts["-f"]
            for h in info["file_handles"]:
                did = h["namespace"] + ":" + h["name"]
                state = h["state"]
                rlist = h["replicas"].values()
                available = state == "ready" and len([r for r in rlist if r["available"]]) > 0
                if filter_state == "all" or \
                            filter_state in ("done", "ready", "failed", "reserved") and state == filter_state or \
                            filter_state == "available" and available or \
                            filter_state == "active" and not state in ("done", "failed"):
                    print(did)
        else:
            print("Project ID:         ", project_id)
            print("Status:             ", info["state"])
            print("Project Attributes: ")
            for k, v in info.get("attributes", {}).items():
                if not isinstance(v, (int, float, str, bool)):
                    v = json.dumps(v)
                print("  %-15s = %s" % (k, v))
            print("Files:              ")
            print_replicas = "-r" in opts
            if "file_handles" in info:
                print_handles(info["file_handles"], print_replicas)
    
list_projects_help = """
list projects     
        -j                                              - JSON output
        -u <owner>                                      - filter by owner
        -s <state>                                      - filter by state
        -a "name=value name=value ..."                  - filter by attributes
"""

def list_projects(client, rest):
    if "help" in rest or "--help" in rest or "-?" in rest:
        print(list_projects_help)
        return
    opts, args = getopt.getopt(rest, "s:a:ju:")
    opts = dict(opts)
    state = opts.get("-s")
    attributes = None
    if "-a" in opts:
        attributes = parse_attrs(opts["-a"])
    owner = opts.get("-u")
    lst = client.list_projects(state=state, attributes=attributes, owner=owner, with_files=True, with_replicas=False)
    if "-j" in opts:
        print(pretty_json(list(lst)))
    else:
        print("%-15s %-15s %-19s %-15s %17s" % ("project id", "owner", "created", "state", "done/failed/files"))
        print("%s %s %s %s %s" % ("-"*15, "-"*15, "-"*19, "-"*15, "-"*17))
        for prj in lst:
            ct = time.localtime(prj["created_timestamp"])
            ct = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            
            nfiles = len(prj["file_handles"])
            ready_files = reserved_files = failed_files = done_files = available_files = 0
            for h in prj["file_handles"]:
                if h["state"] == "ready":
                    ready_files += 1
                elif h["state"] == "done":
                    done_files += 1
                elif h["state"] == "failed":
                    failed_files += 1
            counts = "%d/%d/%d" % (done_files, failed_files, nfiles)
            print("%-15s %-15s %19s %15s %17s" % (prj["project_id"], prj["owner"], ct, prj["state"], counts))
        print("%s %s %s %s %s" % ("-"*15, "-"*15, "-"*19, "-"*15, "-"*17))
    
