import json
import re
import frappe

@frappe.whitelist()
def optimize_routes(pickup_date=None):
    """Optimize routes for all trucks on a given date."""
    if not pickup_date:
        pickup_date = frappe.utils.today()
    
    trucks = frappe.get_list("Truck Profile", 
        filters={"active": 1},
        fields=["name", "truck_name", "total_slots", "weight_capacity"]
    )
    
    pickups = frappe.get_list("Scheduled Pickup",
        filters={
            "pickup_date": pickup_date,
            "shipment_type": "Truck",
            "truck_profile": ["is", "not set"]
        },
        fields=["name", "customer_number", "company_name", "estimated_items", 
                "estimated_weight", "gaylord_count", "gaylord_sizes", "slots_needed",
                "latitude", "longitude"],
        order_by="stop_order asc"
    )
    
    for pickup in pickups:
        if not pickup.slots_needed and pickup.gaylord_sizes:
            pickup.slots_needed = _calculate_slots(pickup.gaylord_sizes)
        elif not pickup.slots_needed:
            pickup.slots_needed = pickup.gaylord_count or 1
    
    pickups.sort(key=lambda x: x.slots_needed or 0, reverse=True)
    
    routes = {}
    for truck in trucks:
        routes[truck.name] = {
            "truck": truck,
            "pickups": [],
            "used_slots": 0,
            "used_weight": 0
        }
    
    unassigned = []
    
    for pickup in pickups:
        assigned = False
        for truck_name, route in routes.items():
            truck = route["truck"]
            slots = pickup.slots_needed or 0
            weight = float(pickup.estimated_weight or 0)
            
            if route["used_slots"] + slots <= truck.total_slots:
                if truck.weight_capacity and route["used_weight"] + weight <= truck.weight_capacity:
                    route["pickups"].append(pickup)
                    route["used_slots"] += slots
                    route["used_weight"] += weight
                    assigned = True
                    frappe.db.set_value("Scheduled Pickup", pickup.name, "truck_profile", truck_name)
                    break
                elif not truck.weight_capacity:
                    route["pickups"].append(pickup)
                    route["used_slots"] += slots
                    route["used_weight"] += weight
                    assigned = True
                    frappe.db.set_value("Scheduled Pickup", pickup.name, "truck_profile", truck_name)
                    break
        if not assigned:
            unassigned.append(pickup)
    
    for truck_name, route in routes.items():
        if route["pickups"]:
            route["pickups"].sort(key=lambda p: (float(p.latitude or 0), float(p.longitude or 0)))
            for i, pickup in enumerate(route["pickups"], 1):
                frappe.db.set_value("Scheduled Pickup", pickup.name, "stop_order", i)
    
    frappe.db.commit()
    
    return {
        "success": True,
        "date": pickup_date,
        "trucks_assigned": len([r for r in routes.values() if r["pickups"]]),
        "total_pickups": len(pickups),
        "unassigned": len(unassigned),
        "routes": {
            truck_name: {
                "truck_name": route["truck"].truck_name,
                "slots_used": route["used_slots"],
                "slots_total": route["truck"].total_slots,
                "weight_used": route["used_weight"],
                "weight_capacity": route["truck"].weight_capacity,
                "stops": len(route["pickups"]),
                "pickups": [{"name": p.name, "company": p.company_name, "slots": p.slots_needed} for p in route["pickups"]]
            }
            for truck_name, route in routes.items() if route["pickups"]
        }
    }

def _calculate_slots(gaylord_sizes_text):
    if not gaylord_sizes_text:
        return 0
    size_map = {"small": 1, "medium": 2, "large": 3}
    total = 0
    matches = re.findall(r'(\d+)\s*(\w+)', gaylord_sizes_text.lower())
    for count, size in matches:
        slots = size_map.get(size, 1)
        total += int(count) * slots
    return total or 1


@frappe.whitelist()
def get_scheduled_pickups(pickup_date=None):
    """Get scheduled pickups for a given date."""
    if not pickup_date:
        pickup_date = frappe.utils.today()
    
    pickups = frappe.get_list("Scheduled Pickup",
        filters={"pickup_date": pickup_date},
        fields=["name", "customer_number", "company_name", "estimated_items",
                 "estimated_weight", "gaylord_count", "gaylord_sizes", "slots_needed",
                 "latitude", "longitude", "stop_order", "truck_profile", "status",
                 "contact_name", "contact_phone", "address_line", "city", "state", "zip_code"],
        order_by="stop_order asc"
    )
    
    return pickups
