from concurrent import futures
import time

import grpc
import greet_pb2
import greet_pb2_grpc

#imported by me
import pandas as pd
import numpy as np
from prophet import Prophet
import matplotlib.pyplot as plt
import time
from sklearn.ensemble import RandomForestRegressor
import datetime as dt
from statistics import mean 

class GreeterServicer(greet_pb2_grpc.GreeterServicer):
    def ComputeTopologyForecast(self, request, context):
        print("The following request has been received:")
        print(request)

        #this value indicates the size of the trainset.
        #For example a history ratio of 10 would imply that the trainset will be 10 times bigger than the testset.
        forecast_to_history_ratio = 10
        #history_window_seconds indicates the size of the trainset based on the requested size of the testset and the predifined history ratio
        history_window_seconds = forecast_to_history_ratio * request.forecast_window_seconds

        df = getTopology(request.topology_id)

        df["ds"] = pd.to_datetime(df["ds"]) - dt.datetime(1970, 1, 1)
        df["ds"] = df["ds"].dt.total_seconds()

        maximum = df["ds"].max()
        minimum = maximum - history_window_seconds
        print(f"The dates of the trainset would have the following range of values: From {minimum} until {maximum} ")
        #smallest = df["ds"].drop_duplicates().nsmallest(2)
        #smallest = smallest.reset_index()
        #sampleDifference = smallest["ds"][1] - smallest["ds"][0]
        #calculating the maximum size of the dataset
        #futureMaximum = sampleDifference * request.forecast_window_seconds
        #futureMaximum = futureMaximum + maximum
        #print(f"Sample frequency: {sampleDifference}")
        #print(f"The testset would have the following range of values: From {maximum} until {futureMaximum} ")

        #filtering by linkId and parsing it into integers
        link_capacity = greet_pb2.LinkCapacity()
        forecast_reply = greet_pb2.ForecastReply()

        for linkid in df["linkid"].unique()[:10]:
            print(linkid)
            newdf = df[df.linkid == linkid ]
            #converting linkid to float to avoid problems with machine learning, since there is only one option. It is converted to 1.0
            newdf.loc[:,"linkid"] = 1.0
            trainset = newdf[int(newdf.shape[0] / 10):newdf.shape[0]]
            testset = newdf[0:int(newdf.shape[0] / 10)]

            rf = RandomForestRegressor(n_estimators = 600, random_state = 42)
            rf.fit(trainset.drop(['y'], axis=1), trainset['y'])

            forecast = rf.predict(testset.drop(['y'], axis=1))
            averageResult = round( mean(testset['y']), 2 )
            maximumCapacity = round( trainset["y"].max(), 2)

            link_capacity.linkuuid = linkid
            link_capacity.forecasted_capacity = averageResult
            link_capacity.total_capacity_gbps = maximumCapacity

            forecast_reply.LinkCapacityList.append(link_capacity)

        
        print("The results were completely generated")

        return forecast_reply
    
def getTopology(topologyId):
    if topologyId == "1":
        df = pd.read_csv('dataset.csv')
    elif topologyId == "2":
        df = pd.read_csv('dataset2.csv')
        print(df.columns)
        #Adapting the dataframe to have the same structure
        df = df.drop(['Unnamed: 0', 'source', 'target'], axis=1)
        df.rename(columns = {'id':'linkid'}, inplace = True)
        df.rename(columns = {'demandValue':'y'}, inplace = True)
    else:
        df = pd.read_csv('./PythonGrpc-main/dataset.csv')
    return df


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    greet_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)
    server.add_insecure_port("localhost:50051")
    server.start()
    server.wait_for_termination()

if __name__ == "__main__":
    serve()