import sys
import os
modules_path = '../../../modules/'
if os.path.exists(modules_path):
    sys.path.insert(1, modules_path)

import json
from datetime import datetime, date
from db.repository import Repository
from db.entities.timeslice import TimeSlice
from db.entities import ClusterSet, Cluster
from typing import Tuple, Dict, Any, List

TimeSliceKey = Tuple[int, int]

def convert_to_time_slice_key(timestamp: str) -> TimeSliceKey:
    '''Returns the tuple (year, week_of_year) from a timestamp. This is used as the key for the slicing.'''
    time = datetime.utcfromtimestamp(float(timestamp[0:10]))
    (y, w, _) = time.isocalendar()
    return (y, w)


def split_clusterset_by_time(layer_name: str, clusters: List[Cluster]) -> Dict[TimeSliceKey, TimeSlice]:
    '''
    Distributes all nodes in clusters of a single layer into individual time slices based on their timestamps. 
    If a node spans over multiple slices it will be added to all of them.
    Information about clusters and the nodes in the clusters will not be changed.

    :params clusters: The clusters whichs nodes are split
    :returns: A dict of time slices where the key is the time info and value is the information about the time slice
    '''
    time_property_names = ['Finished_time', 'Starting_time']

    time_slices: Dict[Any, TimeSlice] = {} 
    for cluster_no in clusters:
        for node in cluster_no.nodes:

            # retrieve times the node is located in based on the defined time properties in the schema
            time_keys = set()
            for time_property in time_property_names:
                if time_property in node:
                    time_keys.add(convert_to_time_slice_key(str(node[time_property])))  

            for time_key in time_keys:
                if time_key not in time_slices:
                    time_slices[time_key] = TimeSlice(time_key, layer_name)

                time_slices[time_key].add_node_to_cluster(cluster_no.cluster_label, node)

    return time_slices
        

if __name__ == "__main__":
    repo = Repository()

    repo.remove_all_time_slices()

    layers = repo.get_layers()
    for layer in layers:
        layer_name = layer.layer_name
        print(f"Working on {layer_name}")

        clusters_for_layer = repo.get_clusters_for_layer(layer_name)
        # if no clusters were generated use one large cluster instead of skipping the layer
        if clusters_for_layer is None or len(clusters_for_layer) == 0:
            clusters_for_layer = [Cluster(layer_name, -1, repo.get_layer_nodes(layer_name))]

        time_slices = split_clusterset_by_time(layer_name, clusters_for_layer)

        for k,v in time_slices.items():
            repo.add_time_slice(v)
