# Phase 2: Vehicle Selection
# Time complexity tests
# Author: Norbert Lovinger; xlovin00@vutbr.cz
# Date: 16th May 2023

import time
import numpy as np
import pandas as pd
import random
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler

# Performance tests
random.seed(123)
total_time = 0
data = pd.DataFrame(columns=["brand_name", "vehicle_number", "latitude", "longitude"])
for i in range(1000):
    start_time = time.time()
    for i in range(100):
        data.loc[i] = [ # type: ignore
                random.choice(["BMW", "Mercedes", "Audi", "Volkswagen", "Skoda", "Kia", "Hyundai", "Ford", "Fiat", "Peugeot"]),
                f"vehicle_{i+1}",
                random.uniform(48.1, 48.3),
                random.uniform(16.3, 16.6)
            ]
    end_time = time.time()
    total_time += end_time - start_time
data = pd.DataFrame(columns=["brand_name", "vehicle_number", "latitude", "longitude"])
creation_time = total_time / 1000
print(f"Average time for generating vehicle location data: {creation_time:.6f} milliseconds.")

data.to_csv("vehicle_locations.csv", index=False)

vehicle_df = pd.read_csv("test_vehicle_locations.csv")

total_time = 0
for i in range(1000):
    start_time = time.time()
    vehicle_df["latitude"] = vehicle_df["latitude"] + np.random.normal(scale=0.01, size=len(vehicle_df))
    vehicle_df["longitude"] = vehicle_df["longitude"] + np.random.normal(scale=0.01, size=len(vehicle_df))
    scaler = StandardScaler()
    vehicle_df[["latitude", "longitude"]] = scaler.fit_transform(vehicle_df[["latitude", "longitude"]])
    end_time = time.time()
    total_time += end_time - start_time
scaller_time = total_time / 1000
print(f"Average time for pertubing and scaling vehicle location data: {scaller_time:.6f} milliseconds.")


total_time = 0
for i in range(100):
    start_time = time.time()
    n_init = 10
    sil_scores = []
    for k in range(2, 21):
        kmeans = KMeans(n_clusters=k, random_state=42)
        kmeans.fit(vehicle_df[["latitude", "longitude"]])
        sil_score = silhouette_score(vehicle_df[["latitude", "longitude"]], kmeans.labels_)
        sil_scores.append(sil_score)

    n_clusters = np.argmax(sil_scores) + 2
    print(f"Optimal number of clusters: {n_clusters}")

    kmeans = KMeans(n_clusters=n_clusters, random_state=42)
    kmeans.fit(vehicle_df[["latitude", "longitude"]])
    vehicle_df["cluster"] = kmeans.labels_
    end_time = time.time()
    total_time += end_time - start_time
kmeans_time = total_time / 100
print(f"Average time for clustering vehicle location to randomly choosed number of clusters: {kmeans_time:.6f} milliseconds.")

scaler = StandardScaler()
vehicle_df[["latitude", "longitude"]] = scaler.inverse_transform(vehicle_df[["latitude", "longitude"]])

vehicle_df.to_csv("vehicle_clusters.csv", index=False)

sil_scores = []
for k in range(2, 21):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(vehicle_df[["latitude", "longitude"]])
    sil_score = silhouette_score(vehicle_df[["latitude", "longitude"]], kmeans.labels_)
    sil_scores.append(sil_score)
n_clusters = np.argmax(sil_scores) + 2

for cluster in range(n_clusters):
    print(f"Cluster {cluster}:")
    vehicles = vehicle_df[vehicle_df['cluster'] == cluster]
    center_lat = vehicles["latitude"].mean()
    center_lon = vehicles["longitude"].mean()
    print(f"Center location: ({center_lat}, {center_lon})")
    for _, row in vehicles.iterrows():
        print(f"Vehicle {row['vehicle_number']}: {row['brand_name']} at ({row['latitude']}, {row['longitude']})")
    print("--------------------")

plt.figure(figsize=(10, 8))
cluster_colors = {cluster: np.random.rand(3,) for cluster in range(n_clusters)}
for cluster in range(n_clusters):
    color = cluster_colors[cluster]
    vehicles = vehicle_df[vehicle_df['cluster'] == cluster]
    center_lat = vehicles["latitude"].mean()
    center_lon = vehicles["longitude"].mean()
    plt.scatter(vehicles["longitude"], vehicles["latitude"], s=50, alpha=0.5, c=[color], label=f"Cluster {cluster}")
    plt.plot(center_lon, center_lat, marker='x', markersize=10, color=color)
plt.legend(loc="lower right")
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.title(f"{n_clusters} Clusters of Vehicle Locations in Vienna")
plt.show()