from time import sleep

from .basefile import BaseAnVILFile
from .basefolder import BaseAnVILFolder


class TableEntriesFile(BaseAnVILFile):
    def __init__(self, name, itemsdict):
        self.name = name
        self.last_modified = "" # #TODO determine if this is ok
        string = "\t".join(
                [f"{x}" for x in itemsdict]
            )
        for i in range(len(list(itemsdict.values())[0])):
            string += "\n" + "\t".join(
                [f"{itemsdict[x][i]}" for x in itemsdict]
            )
        self.buffstr = string
        self.size = len(string)
    
    def get_bytes_handler(self):
        return self.string_to_buffer(self.buffstr)


class RootTablesFolder(BaseAnVILFolder):
    def __init__(self, einfo, wsref):
        self.name = "Tables/"
        self.einfo = einfo
        self.wsref = wsref
        super().__init__(self.name)

    def lazy_init(self):
        for ename in self.einfo:
            attribs = self.einfo[ename]["attributeNames"]
            eid = self.einfo[ename]["idName"]
            tf = TableFolder(ename, eid, attribs, self.wsref)
            self[tf.name] = tf


# terra 'entities' represent tables
class TableFolder(BaseAnVILFolder):
    def __init__(self, etype, eid, attribs, wsref):
        self.name = etype + "/"
        super().__init__(self.name)
        self.type = etype
        self.eid = eid
        self.wsref = wsref
        self.attribs = attribs # column names
    
    def lazy_init(self):
        self.make_contents()

    def make_contents(self):
        base_table = {
            name: [] for name in self.attribs
        }
        linked_files = []
        file_links = {}
        # get remote info
        resp = self.get_entity_info()
        for entry in resp:
            e_attrs = entry["attributes"]
            if entry["entityType"] == "cohort" and "query" in e_attrs:
                linked_files.append(TableDataCohort(entry["name"],e_attrs["query"]))
            for attr in self.attribs:
                addendum = ""
                if attr in e_attrs:
                    val = e_attrs[attr]
                    if val is None:
                        val = ""
                    if type(val) == dict: # if theres more processing, e.g. not a string
                        # mere string attributes
                        if val["itemsType"] == "AttributeValue":
                            addendum = ",".join(val["items"])
                        # dict attributes referring to another entity
                        elif val["itemsType"] == "EntityReference": #TODO is this the best way to handle entity references?
                            addendum = ",".join(
                                [x["entityName"] for x in val["items"]]
                            )
                    else:
                        val = str(val) # enforce string
                        addendum = val
                        # check if its a linkable file
                        efiletype = self.is_linkable_file(val)
                        if efiletype is not None:
                            if efiletype not in file_links:
                                file_links[efiletype] = []
                            file_links[efiletype].append(val)
                base_table[attr].append(addendum)
        
        for method in file_links:
            try:
                fresh_files = method.factory(file_links[method])
                linked_files.extend(fresh_files)
            except Exception as e:
                print(f"AnVILFS ERROR: SKIPPING FILE, could not be resolved due to the following error:")
                print(e)
                continue
        # if there are links, make them externally available by entityname_filename.tsv
        linked_files.append(TableEntriesFile(self.type + "_contents.tsv", base_table))
        for f in linked_files:
            self[f.name] = f

    def get_entity_info(self):
        resp = self.fapi.get_entities(
            self.wsref.namespace.name, 
            self.wsref.name,
            self.type)
        if resp.status_code == 200:
            return resp.json()
        else:
            resp.raise_for_status()



class TableDataCohort(BaseAnVILFile):

    def __init__(self, name, query):
        #query = attribs["query"]
        self.name = name + "_query_results.tsv"
        self.size = 1 # some placeholder? cant lazy load AND init with total size of results
        self.query = query
        self.last_modified = "" # #TODO determine if this is ok

    def get_bytes_handler(self):
        job = self.gc_bigquery_client.query(self.query)
        r = job.result()
        schema_keys = [e.name for e in r.schema]
        string = '\t'.join(schema_keys)
        for row in r:
            string += "\n" + '\t'.join(row.values())
        return self.string_to_buffer(string)
