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

# Step 1: Load and preprocess customer data
def load_data():
    # Replace with your data loading logic (e.g., read from CSV)
    # Example:
    df = pd.read_csv('ecom_data_rfm.csv')
    return df

# Step 2: Feature selection
def select_features(df):
    # Select relevant columns for clustering
    selected_features = df[['Frequency', 'Recency', 'Monetary','rankR','rankF','rankM']]
    return selected_features

# Step 3: Data scaling
def scale_data(data):
    scaler = StandardScaler()
    scaled_data = scaler.fit_transform(data)
    return scaled_data, scaler

# Step 4: Finding optimal K
def find_optimal_k(data):
    # Use the Elbow method to find the optimal number of clusters (K)
    inertia_values = []
    silhouette_scores = []
    k_range = range(2, 11)  # Choose a range of K values to test
    
    for k in k_range:
        kmeans = KMeans(n_clusters=k, random_state=42)
        kmeans.fit(data)
        inertia_values.append(kmeans.inertia_)
        if k > 1:
            silhouette_scores.append(silhouette_score(data, kmeans.labels_))
    
    # Plotting elbow curve
    plt.figure(figsize=(10, 5))
    plt.plot(k_range, inertia_values, marker='o')
    plt.title('Elbow Method for Optimal K')
    plt.xlabel('Number of clusters (K)')
    plt.ylabel('Inertia')
    plt.xticks(k_range)
    plt.grid(True)
    plt.show()
    
    # Plotting silhouette scores
    plt.figure(figsize=(10, 5))
    plt.plot(k_range[1:], silhouette_scores, marker='o')
    plt.title('Silhouette Score for Optimal K')
    plt.xlabel('Number of clusters (K)')
    plt.ylabel('Silhouette Score')
    plt.xticks(k_range)
    plt.grid(True)
    plt.show()

    # Return optimal K based on the above analysis
    optimal_k = silhouette_scores.index(max(silhouette_scores)) + 2  # +2 to adjust for 0-based indexing and starting K=2
    return optimal_k

# Step 5: Apply K-means clustering
def apply_kmeans(data, k):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(data)
    cluster_labels = kmeans.labels_
    centroids = kmeans.cluster_centers_
    return cluster_labels, centroids

# Step 6: Interpret the clusters
def interpret_clusters(df, cluster_labels, centroids, scaler):
    # Inverse transform centroids to interpret them in original scale if needed
    centroids_original = scaler.inverse_transform(centroids)
    
    # Assign cluster labels back to the original dataframe
    df['Cluster'] = cluster_labels
    
    # Analyze each cluster
    cluster_profiles = df.groupby('Cluster').mean()
    cluster_sizes = df['Cluster'].value_counts()
    
    # Print cluster profiles
    for cluster_id, profile in cluster_profiles.iterrows():
        print(f"\nCluster {cluster_id} Profile:")
        print(profile)
        print(f"Size of Cluster {cluster_id}: {cluster_sizes[cluster_id]}")
    
    # Optionally, visualize clusters in the original feature space
    
# Main function to execute steps
def main():
    # Step 1: Load data
    df = load_data()
    
    # Step 2: Feature selection
    selected_features = select_features(df)
    
    # Step 3: Data scaling
    scaled_data, scaler = scale_data(selected_features)
    
    # Step 4: Finding optimal K
    optimal_k = find_optimal_k(scaled_data)
    print(f"Optimal number of clusters (K): {optimal_k}")
    
    # Step 5: Apply K-means clustering
    cluster_labels, centroids = apply_kmeans(scaled_data, optimal_k)
    
    # Step 6: Interpret the clusters
    interpret_clusters(df, cluster_labels, centroids, scaler)

if __name__ == "__main__":
    main()