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

import json
from db.entities import *
from typing import List, Dict, Tuple
from db.repository import Repository, AgiRepository
from processing.clustering.clusterer import Clusterer


DEBUG = False

repo = Repository()
test_repo = AgiRepository()


def run_generic_clustering():
    '''Runs the clustering for all layers found in the repository.'''
    all_layers:List[Layer] = repo.get_layers()

    for layer in all_layers:
        if layer.properties is None or len(layer.properties) == 0:
            continue

        print(f"Clustering {layer.layer_name}")
        clusters = run_clustering_for_layer(layer)
        cluster_set = ClusterSet(layer.layer_name, clusters)
        store_clusterset(cluster_set)


def run_clustering_for_layer(layer: Layer) -> List[Cluster]:
    clusterer = Clusterer()

    res = clusterer.cluster_dataset(
        layer.nodes,
        layer.properties
    )

    return [Cluster(key, value) for key, value in res.items()]

def store_clusterset(cluster_set: ClusterSet):
    repo.add_clusterset(cluster_set)
    # with open(f'clusterset_{cluster_set.layer_name}.txt', 'w') as file:
    #     file.write(json.dumps(cluster_set.to_serializable_dict()))


def run_location_clustering():
    user_clusterer = Clusterer()

    all_location_traces = repo.get_locations()

    cluster_result = user_clusterer.cluster_locations(
        [l.to_serializable_dict() for l in all_location_traces])

    clusters = [LocationCluster(key, value)
                for key, value in cluster_result.items()]

    store_clusters('locations', clusters)


def run_time_clustering():
    clusters: List[TimeCluster] = []
    user_clusterer = Clusterer(epsilon=600)  # clustered within 10 minutes

    all_location_traces = repo.get_locations()

    # for each date in timestamp list
    dates = {trace.timestamp.date() for trace in all_location_traces}
    for cur_date in dates:
        traces_for_cur_date = [
            trace for trace in all_location_traces if trace.timestamp.date() == cur_date]

        # for each hour of that day
        for cur_hour in list(range(24)):
            traces_for_time_slice = [
                trace for trace in traces_for_cur_date if trace.timestamp.hour == cur_hour]

            if len(traces_for_time_slice) == 0:
                continue

            # clustering per hour
            cluster_result = user_clusterer.cluster_times(
                [t.to_serializable_dict() for t in traces_for_time_slice])
            cur_clusters = [TimeCluster(cur_date, cur_hour, key, value)
                            for key, value in cluster_result.items()]

            clusters.extend(cur_clusters)

    store_clusters('times', clusters)


def store_clusters(type: str, clusters: List):
    if DEBUG:
        print(clusters)
        return

    if type == 'locations':
        for c in clusters:
            repo.add_location_cluster(c)

    if type == 'times':
        for c in clusters:
            repo.add_time_cluster(c)


if __name__ == "__main__":
    run_generic_clustering()

    # run_location_clustering()
    # run_time_clustering()
