
import logging
from typing import List, Dict, Any

logger = logging.getLogger(__name__)

class ZoneService:
    """
    Service to classify orders and riders into geographic zones.
    Defaulting to Coimbatore logic as per user context.
    """
    
    # Approximate Center of Coimbatore (Gandhipuram/Bus Stand area)
    CENTER_LAT = 11.0168
    CENTER_LON = 76.9558
    
    def __init__(self):
        pass

    def determine_zone(self, lat: float, lon: float) -> str:
        """
        Determine the zone (North, South, East, West, etc.) based on coordinates.
        """
        if lat == 0 or lon == 0:
            return "Unknown"

        lat_diff = lat - self.CENTER_LAT
        lon_diff = lon - self.CENTER_LON
        
        # Simple Quadrant Logic
        # North: +Lat
        # South: -Lat
        # East: +Lon
        # West: -Lon
        
        # Define a small central buffer (0.01 degrees ~ 1.1km)
        buffer = 0.010
        
        is_north = lat_diff > buffer
        is_south = lat_diff < -buffer
        is_east = lon_diff > buffer
        is_west = lon_diff < -buffer
        
        zone_parts = []
        
        if is_north: zone_parts.append("North")
        elif is_south: zone_parts.append("South")
        
        if is_east: zone_parts.append("East")
        elif is_west: zone_parts.append("West")
        
        if not zone_parts:
            return "Central"
            
        return " ".join(zone_parts)

    def group_by_zones(self, flat_orders: List[Dict[str, Any]], unassigned_orders: List[Dict[str, Any]] = None, fuel_charge: float = 2.5, base_pay: float = 0.0) -> Dict[str, Any]:
        """
        Group a flat list of optimized orders into Zones -> Riders -> Orders.
        Calculates profit per order and per zone.
        """
        zones_map = {} # "North East": { "riders": { rider_id: [orders] } }
        unassigned_orders = unassigned_orders or []
        
        # Merge both for initial processing if you want everything zoned
        all_to_process = []
        for o in flat_orders:
            all_to_process.append((o, True))
        for o in unassigned_orders:
            all_to_process.append((o, False))

        for order, is_assigned in all_to_process:
            # 1. Extract Coords
            try:
                # Prefer Delivery location for zoning (where the customer is)
                lat = float(order.get("deliverylat") or order.get("droplat") or 0)
                lon = float(order.get("deliverylong") or order.get("droplon") or 0)
                pincode = str(order.get("deliveryzip") or "")
            except:
                lat, lon, pincode = 0, 0, ""
            
            # 2. Get Zone
            zone_name = self.determine_zone(lat, lon)
            order["zone_name"] = zone_name
            
            # 3. Initialize Zone Bucket
            if zone_name not in zones_map:
                zones_map[zone_name] = {
                    "riders_map": {}, 
                    "total_orders": 0,
                    "assigned_orders": 0,
                    "unassigned_orders": [],
                    "total_kms": 0.0,
                    "total_profit": 0.0
                }
            
            # 4. Add to Rider bucket within Zone
            rider_id = order.get("userid") or order.get("_id")
            
            # Track kms and profit for this zone
            try:
                # 'actualkms' is preferred for delivery distance
                dist = float(order.get("actualkms", order.get("previouskms", 0)))
                zones_map[zone_name]["total_kms"] += dist
                
                # Individual charge for this order: Fixed Base + Variable Distance
                order_amount = float(order.get("orderamount") or order.get("deliveryamount") or 0)
                rider_payment = dist * fuel_charge
                profit = order_amount - rider_payment
                
                order["rider_charge"] = round(rider_payment, 2)
                order["profit"] = round(profit, 2)

                # ── PROFIT CLASS (separate from ordertype) ───────────────
                # `ordertype` is set by route_optimizer based on delivery
                # DISTANCE (Economy ≤5km, Premium ≤12km, Risky >12km).
                # Overwriting it here with a profit-based label broke ETA
                # calculations and downstream routing logic.
                # Use `profit_class` for profit-based analytics instead.
                if profit <= 0:
                    order["profit_class"] = "Loss"
                elif profit <= 5:
                    order["profit_class"] = "Marginal"
                elif profit <= 10:
                    order["profit_class"] = "Profitable"
                else:
                    order["profit_class"] = "HighMargin"

                zones_map[zone_name]["total_profit"] += profit
            except:
                pass

            # If strictly unassigned order (no rider), put in unassigned
            if not is_assigned:
                zones_map[zone_name]["unassigned_orders"].append(order)
            else:
                str_rid = str(rider_id)
                if str_rid not in zones_map[zone_name]["riders_map"]:
                    zones_map[zone_name]["riders_map"][str_rid] = {
                        "rider_details": {
                            "id": str_rid,
                            "name": order.get("username", "Unknown")
                        },
                        "orders": []
                    }
                zones_map[zone_name]["riders_map"][str_rid]["orders"].append(order)
                zones_map[zone_name]["assigned_orders"] += 1
            
            zones_map[zone_name]["total_orders"] += 1

        # 5. Restructure for API Response
        output_zones = []
        zone_metrics = []
        
        sorted_zone_names = sorted(zones_map.keys())
        
        for z_name in sorted_zone_names:
            z_data = zones_map[z_name]
            
            # Flatten riders map
            riders_list = []
            for r_id, r_data in z_data["riders_map"].items():
                riders_list.append({
                    "rider_id": r_data["rider_details"]["id"],
                    "rider_name": r_data["rider_details"]["name"],
                    "orders_count": len(r_data["orders"]),
                    "orders": r_data["orders"]
                })
            
            # Create the flat metric summary
            metrics = {
                "zone_name": z_name,
                "total_orders": z_data["total_orders"],
                "assigned_orders": z_data["assigned_orders"],
                "unassigned_orders_count": len(z_data["unassigned_orders"]),
                "active_riders_count": len(riders_list),
                "total_delivery_kms": round(z_data["total_kms"], 2),
                "total_profit": round(z_data["total_profit"], 2)
            }
            
            zone_metrics.append(metrics)
            
            # Create the detailed zone object with flattened metrics
            zone_obj = {
                "zone_name": z_name,
                "total_orders": metrics["total_orders"],
                "active_riders_count": metrics["active_riders_count"],
                "assigned_orders": metrics["assigned_orders"],
                "unassigned_orders_count": metrics["unassigned_orders_count"],
                "total_delivery_kms": metrics["total_delivery_kms"],
                "total_profit": metrics["total_profit"],
                "riders": riders_list,
                "unassigned_orders": z_data["unassigned_orders"]
            }
            
            output_zones.append(zone_obj)
            
        return {
            "detailed_zones": output_zones,
            "zone_analysis": zone_metrics
        }
