import pandas as pd
import numpy as np
from typing import List, Tuple, Dict
from src.analysis.geospatial import haversine_distance
from src.utils import get_grouping_radius_m
from src.config import config
import logging

logger = logging.getLogger(__name__)

def group_turbines_by_proximity(turbine_df: pd.DataFrame, max_distance_m: int = None) -> List[List[int]]:
    """
    Group turbines based on proximity within max_distance_m meters.
    Returns list of groups, where each group is a list of turbine indices.
    """
    if max_distance_m is None:
        max_distance_m = get_grouping_radius_m()
    try:
        from sklearn.cluster import DBSCAN
        import numpy as np
        coords = np.radians(turbine_df[['lat', 'lng']].values)
        eps_rad = (max_distance_m / 1000.0) / 6371.0
        clustering = DBSCAN(eps=eps_rad, min_samples=1, metric='haversine').fit(coords)
        labels = clustering.labels_
        groups = []
        for label in sorted(set(labels)):
            idxs = np.where(labels == label)[0].tolist()
            groups.append(idxs)
        return groups
    except Exception:
        n_turbines = len(turbine_df)
        groups = []
        assigned = set()
        for i in range(n_turbines):
            if i in assigned:
                continue
            current_group = [i]
            assigned.add(i)
            for j in range(i + 1, n_turbines):
                if j in assigned:
                    continue
                distance = haversine_distance(
                    turbine_df.iloc[i]['lat'], turbine_df.iloc[i]['lng'],
                    turbine_df.iloc[j]['lat'], turbine_df.iloc[j]['lng']
                )
                if distance <= max_distance_m:
                    current_group.append(j)
                    assigned.add(j)
            groups.append(current_group)
        return groups

def calculate_group_centroid(turbine_df: pd.DataFrame, group_indices: List[int]) -> Tuple[float, float]:
    """
    Calculate the centroid (center point) of a group of turbines.
    Returns (lat, lng) of the centroid.
    """
    if not group_indices:
        return 0.0, 0.0
    
    lats = turbine_df.iloc[group_indices]['lat'].values
    lngs = turbine_df.iloc[group_indices]['lng'].values
    
    centroid_lat = np.mean(lats)
    centroid_lng = np.mean(lngs)
    
    return centroid_lat, centroid_lng

def create_turbine_groups(turbine_df: pd.DataFrame) -> Dict:
    """
    Create turbine groups and calculate their centroids.
    Returns a dictionary with group information.
    """
    groups = group_turbines_by_proximity(turbine_df)
    
    group_data = []
    for i, group_indices in enumerate(groups):
        centroid_lat, centroid_lng = calculate_group_centroid(turbine_df, group_indices)
        
        group_info = {
            'group_id': i,
            'turbine_indices': group_indices,
            'centroid_lat': centroid_lat,
            'centroid_lng': centroid_lng,
            'turbine_count': len(group_indices),
            'is_single': len(group_indices) == 1
        }
        group_data.append(group_info)
    
    return {
        'groups': group_data,
        'total_groups': len(groups),
        'total_turbines': len(turbine_df)
    } 