"""
Main FastAPI Application for DispoManager - Flottenmanagement & Tourenplanung
==============================================================================
Kernfunktionalität:
- Fahrzeugverwaltung
- Auftragseingang & Tourenplanung
- Optimierungsalgorithmen (Route Planning)
- Live-Tracking Simulation
- Berichtswesen
"""

from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel, Field
import json
import uuid
from typing import List, Optional
from datetime import datetime

# Importe eigene Module (werden im App-Container erstellt)
try:
    from vehicle import Vehicle, create_vessels
except ImportError:
    pass  # Wird später geladen


app = FastAPI(
    title="DispoManager API",
    description="Flottenmanagement & Tourenplanungs-System für Contado/Cargo Support",
    version="1.0.0"
)

# === IN-MEMORY DATA STORES (für Entwicklung/Testing) ===

# Fahrzeugdatenbank
vehicles: dict[str, dict] = {}

# Bestellungen / Aufträge
orders: list[dict] = []

# Tourenplanungen
tours: list[dict] = []

# Fahrzeuge initialisieren
def create_demo_vessels():
    """Erstellt Demo-Fahrzeuge"""
    vessel_types = [
        {"name": "Schlepper", "capacity": 20, "cost_per_km": 0.15},
        {"name": "Laster-4x2", "capacity": 8, "cost_per_km": 0.12},
        {"name": "Laster-3.5t", "capacity": 3.5, "cost_per_km": 0.08},
        {"name": "Kleintransporter", "capacity": 1.2, "cost_per_km": 0.05},
    ]
    
    for i, vtype in enumerate(vessel_types):
        for j in range(3):  # 3 Stück pro Typ
            vid = f"vhc-{i*3+j+1:03d}"
            vehicles[vid] = {
                "id": vid,
                "name": f"{vtype['name']} #{j+1}",
                "type": vtype["name"],
                "capacity": vtype["capacity"],
                "cost_per_km": vtype["cost_per_km"],
                "status": "verfuegbar",
                "current_location": {"x": 50, "y": 50},  # Koordinaten (0-100)
                "current_order": None,
                "total_distance": 0,
            }

# Demo-Daten erstellen
create_demo_vessels()


# === REQUEST/RESPONSE MODELS ===

class OrderCreate(BaseModel):
    name: str
    pickup_location: dict[str, int] = Field(..., description="{'x': float, 'y': float}")
    delivery_location: dict[str, int] = Field(...)
    quantity: float
    priority: str = Field(default="normal", pattern="^(low|normal|high)$")
    deadline: Optional[str] = None

class TourCreate(BaseModel):
    vehicle_id: str
    orders: List[str]


# === API ENDPOINTS ===

@app.get("/")
async def root():
    """API Status & Info"""
    return {
        "service": "DispoManager API",
        "status": "running",
        "endpoints": [
            "/orders" + " - Bestellungen verwalten",
            "/vehicles" + " - Fahrzeuge verwalten", 
            "/tours" + " - Touren planen",
            "/optimize" + " - Touren optimieren",
            "/status/heatmap" + " - Live-Tracking Heatmap",
        ],
        "demo_data": {
            "vehicles_count": len(vehicles),
            "orders_count": len(orders),
            "tours_count": len(tours),
        }
    }


@app.get("/orders")
async def list_orders():
    """Bestellungen auflisten"""
    return {
        "orders": orders,
        "total_count": len(orders)
    }


@app.post("/orders")
async def create_order(order: OrderCreate):
    """Neue Bestellung anlegen"""
    order_id = f"ord-{uuid.uuid4().hex[:8]}"
    
    new_order = {
        "id": order_id,
        "name": order.name,
        "pickup_location": order.pickup_location,
        "delivery_location": order.delivery_location,
        "quantity": order.quantity,
        "priority": order.priority,
        "deadline": order.deadline,
        "status": "pending",
        "assigned_vehicle": None,
        "route": None,
        "created_at": datetime.now().isoformat(),
    }
    
    orders.append(new_order)
    
    return {
        "message": f"Bestellung '{order.name}' angelegt",
        "order_id": order_id,
        "details": new_order
    }


@app.get("/vehicles")
async def list_vehicles():
    """Fahrzeuge auflisten"""
    return {
        "vehicles": vehicles.values(),
        "available_count": sum(1 for v in vehicles.values() if v["status"] == "verfuegbar"),
        "in_use_count": len(vehicles) - sum(1 for v in vehicles.values() if v["status"] == "verfuegbar")
    }


@app.get("/vehicles/{vehicle_id}")
async def get_vehicle(vehicle_id: str):
    """Einzelnes Fahrzeug details"""
    if vehicle_id not in vehicles:
        raise HTTPException(status_code=404, detail=f"Fahrzeug '{vehicle_id}' nicht gefunden")
    
    return {"vehicle": vehicles[vehicle_id]}


@app.post("/vehicles/{vehicle_id}/assign")
async def assign_vehicle_to_order(vehicle_id: str, order_name: str):
    """Fahrzeug einer Bestellung zuweisen"""
    # Prüfen ob Fahrzeug existiert
    if vehicle_id not in vehicles:
        raise HTTPException(status_code=404, detail=f"Fahrzeug '{vehicle_id}' nicht gefunden")
    
    # Find order by name
    order = next((o for o in orders if o["name"] == order_name), None)
    if not order:
        raise HTTPException(status_code=404, detail=f"Bestellung '{order_name}' nicht gefunden")
    
    vehicle = vehicles[vehicle_id]
    
    # Check capacity
    current_load = sum(
        next(o["quantity"] for o in orders 
             if o["assigned_vehicle"] == vehicle_id)["quantity"] 
        for _ in [1]  # workaround
    )
    actual_load = 0
    if order["assigned_vehicle"]:
        assigned_order = next((o for o in orders if o["id"] == order["assigned_vehicle"]), None)
        if assigned_order:
            actual_load = assigned_order.get("quantity", 0)
    
    if current_load + order["quantity"] > vehicle["capacity"]:
        raise HTTPException(
            status_code=400, 
            detail=f"Fahrzeug '{vehicle['name']}' hat Kapazität '{vehicle['capacity']}', "
                    f"aktuelle Last: '{current_load}' + Neulast: '{order['quantity']}' > Max!"
        )
    
    # Zuweisen
    vehicle["status"] = "in_use"
    order["assigned_vehicle"] = vehicle_id
    order["status"] = "assigned"
    
    return {
        "message": f"Fahrzeug '{vehicle['name']}' zugewiesen",
        "vehicle": vehicles[vehicle_id],
        "order": order
    }


@app.post("/optimize")
async def optimize_routes():
    """Optimiert Tourenplanung (Einfacher Greedy-Algorithmus)"""
    
    available_vehicles = [
        vid for vid, v in vehicles.items() 
        if v["status"] == "verfuegbar" and v["capacity"] > 0
    ]
    
    pending_orders = [o for o in orders if o["status"] == "pending"]
    
    if not available_vehicles or not pending_orders:
        return {
            "message": "Keine verfügbaren Fahrzeuge oder Bestellungen zu optimieren",
            "available_vehicles_count": len(available_vehicles),
            "pending_orders_count": len(pending_orders)
        }
    
    # Sort orders by priority
    priority_order = {"high": 0, "normal": 1, "low": 2}
    pending_orders.sort(key=lambda o: (priority_order.get(o["priority"], 1), -o["quantity"]))
    
    optimized_tours = []
    
    for vid in available_vehicles:
        vehicle = vehicles[vid]
        
        # Greedy-Algo: Nächste passende Bestellung finden
        if pending_orders:
            order_idx = 0
            best_order = None
            
            # Finde passende Bestellung (Priorität beachten)
            for i, order in enumerate(pending_orders):
                can_fulfill = (vehicle["capacity"] - vehicle.get("current_load", 0)) >= order["quantity"]
                
                if can_fulfill:
                    best_order = order
                    order_idx = i
                    break
            
            # Order "laden"
            if best_order and order_idx < len(pending_orders):
                pending_orders.pop(order_idx)
                
                vehicle["status"] = "in_use"
                best_order["assigned_vehicle"] = vid
                best_order["status"] = "assigned"
                vehicle["current_order"] = best_order["name"]
                
                # Route berechnen (einfach: Pickup -> Delivery)
                route = calculate_route(
                    vehicle["current_location"],
                    best_order["pickup_location"],
                    best_order["delivery_location"]
                )
                
                tour = {
                    "id": f"tour-{len(optimized_tours)+1:03d}",
                    "vehicle_id": vid,
                    "vehicle_name": vehicle["name"],
                    "orders": [best_order["id"]],
                    "pickup_location": best_order["pickup_location"],
                    "delivery_location": best_order["delivery_location"],
                    "total_distance": route.get("distance", 0),
                    "estimated_cost": route.get("cost", 0),
                    "status": "scheduled"
                }
                
                optimized_tours.append(tour)
                
    return {
        "message": f"{len(optimized_tours)} Touren optimiert",
        "tours": optimized_tours,
        "remaining_orders": len(pending_orders)
    }


@app.get("/status/heatmap")
async def status_heatmap():
    """Live-Tracking Heatmap Daten"""
    
    vehicle_locations = []
    for vid, v in vehicles.items():
        if v["current_location"]:
            loc = v["current_location"]
            color = "green" if v["status"] == "verfuegbar" else ("orange" if v.get("current_order") else "red")
            vehicle_locations.append({
                "x": loc.get("x", 50),
                "y": loc.get("y", 50),
                "vehicle_id": vid,
                "color": color,
                "status": v["status"]
            })
    
    order_locations = []
    for order in orders:
        if order["pickup_location"]:
            pickup = order["pickup_location"]
            delivery = order["delivery_location"]
            
            # Status basierend auf Order-Zustand
            status_color = {
                "pending": "gray",
                "assigned": "orange",
                "in_progress": "yellow"
            }.get(order.get("status"), "blue")
            
            if pickup:
                order_locations.append({
                    "type": "pickup",
                    **pickup,
                    "order_id": order["id"],
                    "status": order.get("status", "pending"),
                    "color": status_color
                })
            if delivery:
                order_locations.append({
                    "type": "delivery",
                    **delivery,
                    "order_id": order["id"],
                    "status": order.get("status", "pending"),
                    "color": status_color
                })
    
    return {
        "timestamp": datetime.now().isoformat(),
        "vehicles": vehicle_locations,
        "orders": order_locations,
        "legend": {
            "green": "Fahrzeug verfügbar",
            "orange": "Fahrzeug ausgelastet",
            "red": "Fahrzeug unbelastbar",
            "blue": "Order-Pickup/Lieferung"
        }
    }


def calculate_route(start: dict, via1: dict, via2: dict):
    """Berechnet einfache Route (Euklidische Distanz)"""
    
    # Start -> Via1
    dx1 = via1["x"] - start["x"]
    dy1 = via1["y"] - start["y"]
    dist1 = (dx1**2 + dy1**2)**0.5
    
    # Via1 -> Via2  
    dx2 = via2["x"] - via1["x"]
    dy2 = via2["y"] - via1["y"]
    dist2 = (dx2**2 + dy2**2)**0.5
    
    total_distance = dist1 + dist2
    cost = vehicle_avg_cost_per_km * total_distance / 100  # Skalierung
    
    return {
        "distance": round(total_distance, 2),
        "cost": round(cost, 2),
        "waypoints": [start, via1, via2]
    }
