import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score, davies_bouldin_score

# =========================================================
# ?? EINSTELLUNGEN
# =========================================================

RANDOM_SEED = 42
MAX_K = 8
POINTS_PER_CLUSTER = 100

# echte Cluster (für Simulation)
CENTER_1 = [0, 0]
CENTER_2 = [6, 6]
CENTER_3 = [0, 6]

# =========================================================
# 1. DATEN GENERIEREN
# =========================================================

np.random.seed(RANDOM_SEED)

data1 = np.random.randn(POINTS_PER_CLUSTER, 2) + CENTER_1
data2 = np.random.randn(POINTS_PER_CLUSTER, 2) + CENTER_2
data3 = np.random.randn(POINTS_PER_CLUSTER, 2) + CENTER_3

X = np.vstack((data1, data2, data3))

# =========================================================
# 2. ELBOW + GÜTEMASSE
# =========================================================

k_values = range(1, MAX_K + 1)
inertia_values = []
silhouette_values = []
db_values = []

for k in k_values:
    kmeans = KMeans(n_clusters=k, random_state=RANDOM_SEED, n_init=10)
    kmeans.fit(X)

    inertia_values.append(kmeans.inertia_)

    if k >= 2:
        labels = kmeans.labels_
        silhouette_values.append(silhouette_score(X, labels))
        db_values.append(davies_bouldin_score(X, labels))
    else:
        silhouette_values.append(np.nan)
        db_values.append(np.nan)

# =========================================================
# 3. BESTES k (vereinfacht: nach Silhouette)
# =========================================================

best_k = k_values[np.nanargmax(silhouette_values)]

# Frage:
# Warum nehmen wir hier Silhouette und nicht Inertia?
# Lösung:
# ? Inertia sinkt immer ? kein klares Optimum

# =========================================================
# 4. FINALES MODELL
# =========================================================

kmeans_final = KMeans(n_clusters=best_k, random_state=RANDOM_SEED, n_init=10)
kmeans_final.fit(X)

labels_final = kmeans_final.labels_
centers_final = kmeans_final.cluster_centers_

# =========================================================
# 5. VISUALISIERUNG
# =========================================================

fig, ax = plt.subplots(1, 4, figsize=(20, 4))

# ---- Originaldaten ----
ax[0].scatter(X[:, 0], X[:, 1])
ax[0].set_title("Rohdaten (unclustered)")

# Frage:
# Siehst du hier schon Cluster?
# Lösung:
# ? Ja, visuell oft erkennbar, aber nicht immer eindeutig

# ---- Elbow ----
ax[1].plot(k_values, inertia_values, marker="o")
ax[1].set_title("Elbow (Inertia)")
ax[1].set_xlabel("k")
ax[1].set_ylabel("Fehler")

# ---- Silhouette ----
ax[2].plot(k_values, silhouette_values, marker="o")
ax[2].set_title("Silhouette Score")
ax[2].set_xlabel("k")

# ---- Finales Clustering ----
scatter = ax[3].scatter(X[:, 0], X[:, 1], c=labels_final)
ax[3].scatter(centers_final[:, 0], centers_final[:, 1], c="red", s=200, marker="X")
ax[3].set_title(f"K-Means Ergebnis (k={best_k})")

# Frage:
# Warum sind die Cluster farbig getrennt?
# Lösung:
# - Hard Clustering: jeder Punkt genau ein Label

plt.tight_layout()
plt.savefig("plots/elbow_measures.png", dpi=150, bbox_inches="tight")
print("Plot gespeichert: plots/elbow_measures.png")

# =========================================================
# ? WEITERE FRAGEN
# =========================================================

# Frage:
# Was passiert, wenn wir die Daten stärker überlappen lassen?
# Lösung:
# ? Clustering wird schwieriger, Scores schlechter

# Frage:
# Warum können verschiedene Runs unterschiedliche Ergebnisse liefern?
# Lösung:
# ? zufällige Initialisierung der Zentren

# Frage:
# Ist das gefundene k immer korrekt?
# Lösung:
# ? Nein, nur heuristisch bestimmt
