from fastapi import FastAPI, HTTPException, status, APIRouter 
from typing import List, Any, Optional
from pymongo import MongoClient
from bson.objectid import ObjectId
from dotenv import load_dotenv
from pydantic import BaseModel, Field, ConfigDict
from pymongo.errors import ServerSelectionTimeoutError

import os
from datetime import datetime
import locale
from locale import setlocale, LC_TIME
import uvicorn 

load_dotenv()

# --- FUNCIÓN DE FECHA Y HORA AUXILIARES (Sin Cambios) ---
try:
    locale.setlocale(LC_TIME, 'es_ES.UTF-8')
except locale.Error:
    try:
        locale.setlocale(LC_TIME, 'es_ES')
    except locale.Error:
        try:
            locale.setlocale(LC_TIME, 'Spanish_Spain')
        except locale.Error:
            pass 

def get_current_date_in_format_day_only():
    now = datetime.now()
    return now.strftime("%A %#d de %b de %Y").replace('.', '').capitalize()

def get_current_time_in_format_hour_only():
    now = datetime.now()
    return now.strftime("%H:%M")

# --- MODELOS (Sin Cambios) ---
class MCPTransportista(BaseModel):
    whatsapp: str
    nombre: str

class MCPVehiculo(BaseModel):
    placa: str
    carga_maxima: float

class RegistroTransportistaBody(BaseModel):
    transportista: MCPTransportista
    vehiculo: MCPVehiculo
    
class Vehiculo(BaseModel):
    placa: str = Field(..., description="Matrícula única del vehículo.")
    carga_maxima: float = Field(..., gt=0, description="Capacidad máxima de carga en toneladas.")

class MongoBaseModel(BaseModel):
    id: Optional[str] = Field(alias="_id", default=None)
    model_config = ConfigDict(
        populate_by_name=True,
        json_schema_extra={"example": {"id": "60d5ec49b14f6b3d4f4d4e3a"}}
    )

class Transportista(MongoBaseModel):
    nombre: str = Field(..., description="Nombre completo del transportista.")
    telefono_whatsapp: str = Field(..., description="Número de contacto principal (whatsapp).")
    vehiculos: List[Vehiculo] = Field(default_factory=list, description="Lista de vehículos asociados.")

class OrdenDeServicio(MongoBaseModel):
    whatsappCliente: str
    nombreCliente: str
    carga: str = Field(..., description="Descripción detallada de la carga.")
    peso_aproximado: Optional[float] = Field(None, description="Peso estimado de la carga.")
    origen: str
    destino: str
    estado: str = "pendiente"
    fecha: str = Field(default_factory=get_current_date_in_format_day_only)
    hora: str = Field(default_factory=get_current_time_in_format_hour_only)
    
# --- CONFIGURACIÓN DE FASTAPI Y CONEXIÓN A MONGO ---

# 🌟 1. Se añade el root_path a la aplicación principal de FastAPI
app = FastAPI(title="API MOVILIZIA", root_path="/api-movilizia")
router = APIRouter() 

MONGO_URI = os.getenv("MONGO_URI")
MONGO_DB_NAME = os.getenv("MONGO_DB_NAME")

client: MongoClient = None
db: Any = None

@app.on_event("startup")
def startup_db_client():
    global client, db
    
    if not MONGO_URI or not MONGO_DB_NAME:
        raise ValueError("MONGO_URI y MONGO_DB_NAME deben estar definidos.")
    try:
        client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=5000) 
        client.admin.command('ping') 
        db = client[MONGO_DB_NAME]
        print(f"Conectado a MongoDB: {MONGO_DB_NAME}")
    except (ServerSelectionTimeoutError, Exception) as e: 
        print(f"ERROR FATAL AL CONECTAR A MONGO: {e}")
        db = None 

@app.on_event("shutdown")
def shutdown_db_client():
    global client
    if client:
        client.close()
        print("Conexión a MongoDB cerrada.")

# --- HELPERS (Sin Cambios) ---
def validate_object_id(id: str):
    try:
        return ObjectId(id)
    except Exception:
        raise HTTPException(status_code=400, detail="ID inválido")

# ======================================================================
# --- ENDPOINTS: TRANSPORTISTAS ---
# ======================================================================

@router.post(
    "/transportistas/register",
    response_model=Transportista,
    status_code=status.HTTP_201_CREATED,
    tags=["Transportistas"]
)
def register_transportista_and_vehicle_unified(request_body: RegistroTransportistaBody):
    """Registra un Transportista y su Vehículo."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Error al registrar: DB no activa.")
    
    nuevo_transportista = Transportista(
        nombre=request_body.transportista.nombre,
        telefono_whatsapp=request_body.transportista.whatsapp,
        vehiculos=[
            Vehiculo(placa=request_body.vehiculo.placa, carga_maxima=request_body.vehiculo.carga_maxima)
        ]
    )
    data_to_insert = nuevo_transportista.model_dump(by_alias=True, exclude_none=True)
    if 'id' in data_to_insert: data_to_insert.pop("id")
    
    try:
        result = db.transportistas.insert_one(data_to_insert)
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error DB: {e}")

    created = db.transportistas.find_one({"_id": result.inserted_id})
    if created and created.get('_id'): created['_id'] = str(created['_id'])
    return Transportista.model_validate(created, from_attributes=True)


@router.get("/transportistas/", response_model=List[Transportista], tags=["Transportistas"])
def read_transportistas():
    """Lee todos los transportistas."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Error al listar: DB no activa.")
        
    try:
        results = db.transportistas.find()
        validated_results = []
        for doc in results:
            if doc.get('_id'): doc['_id'] = str(doc['_id'])
            validated_results.append(Transportista.model_validate(doc, from_attributes=True))
        return validated_results
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error DB: {e}")

# ✅ NUEVO ENDPOINT: Buscar transportista por número de WhatsApp
@router.get("/transportistas/{whatsapp}", response_model=Transportista, tags=["Transportistas"])
def get_transportista_by_whatsapp(whatsapp: str):
    """Busca un transportista por su número de WhatsApp."""
    global db
    if db is None:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Error: DB no activa."
        )
    
    try:
        transportista = db.transportistas.find_one({"telefono_whatsapp": whatsapp})
        if not transportista:
            # Si no existe, lanzamos un 404 limpio
            raise HTTPException(
                status_code=404,
                detail=f"No se encontró transportista con WhatsApp {whatsapp}"
            )

        transportista["_id"] = str(transportista["_id"])
        return Transportista.model_validate(transportista, from_attributes=True)

    except HTTPException as e:
        # ⚙️ Propagamos los errores controlados (como 404)
        raise e
    except Exception as e:
        # 🔁 Solo los errores no controlados dan 400
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Error DB: {e}"
        )



# ✅ NUEVO ENDPOINT: Eliminar transportista por número de WhatsApp
@router.delete("/transportistas/{whatsapp}", status_code=status.HTTP_200_OK, tags=["Transportistas"])
def delete_transportista_by_whatsapp(whatsapp: str):
    """Elimina un transportista por su número de WhatsApp."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Error: DB no activa.")
    
    try:
        result = db.transportistas.delete_one({"telefono_whatsapp": whatsapp})
        if result.deleted_count == 0:
            raise HTTPException(status_code=404, detail=f"No se encontró transportista con WhatsApp {whatsapp}")
        return {"message": f"Transportista con WhatsApp {whatsapp} eliminado correctamente."}
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error DB: {e}")


# ======================================================================
# --- ENDPOINTS: ÓRDENES DE SERVICIO ---
# ======================================================================

@router.post(
    "/ordenes/", response_model=OrdenDeServicio, status_code=status.HTTP_201_CREATED, tags=["Órdenes de Servicio"]
)
def create_orden(orden_data: OrdenDeServicio):
    """Crea una nueva orden de servicio."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Error al crear: DB no activa.")
        
    data = orden_data.model_dump(by_alias=True, exclude_none=True)
    if 'id' in data: data.pop("id")
    
    try:
        result = db.ordenes.insert_one(data)
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error al crear orden en la DB: {e}")
        
    created = db.ordenes.find_one({"_id": result.inserted_id})
    if created and created.get('_id'): created['_id'] = str(created['_id'])
    return OrdenDeServicio.model_validate(created, from_attributes=True)

@router.get("/ordenes/", response_model=List[OrdenDeServicio], tags=["Órdenes de Servicio"])
def read_ordenes():
    """Lee todas las órdenes de servicio."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Error al listar: DB no activa.")
        
    try:
        results = db.ordenes.find()
        validated_results = []
        for doc in results:
            if doc.get('_id'): doc['_id'] = str(doc['_id'])
            validated_results.append(OrdenDeServicio.model_validate(doc, from_attributes=True))
        return validated_results
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error al listar órdenes: {e}")

@router.get("/ordenes/{orden_id}", response_model=OrdenDeServicio, tags=["Órdenes de Servicio"])
def get_orden_by_id(orden_id: str):
    """Busca una orden por su ID."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="DB no activa.")
    
    obj_id = validate_object_id(orden_id)
    
    orden = db.ordenes.find_one({"_id": obj_id})
    if not orden:
        raise HTTPException(status_code=404, detail=f"No se encontró la orden con ID {orden_id}")
    
    orden['_id'] = str(orden['_id'])
    return OrdenDeServicio.model_validate(orden, from_attributes=True)

    
# Modelo para actualizar orden + transportista
class UpdateOrdenTransportistaBody(BaseModel):
    id: str
    nuevo_estado: Optional[str] = None
    whatsapp_transportista: Optional[str] = None
    nombre_transportista: Optional[str] = None

@router.patch("/ordenes/actualizar", response_model=OrdenDeServicio, tags=["Órdenes de Servicio"])
def update_orden_y_transportista(request_body: UpdateOrdenTransportistaBody):
    """Actualiza el estado de la orden y los datos del transportista asociados."""
    global db
    if db is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="DB no activa.")

    obj_id = validate_object_id(request_body.id)

    try:
        # Buscar la orden
        orden = db.ordenes.find_one({"_id": obj_id})
        if not orden:
            raise HTTPException(status_code=404, detail=f"No se encontró la orden con ID {request_body.id}")

        update_data = {}
        if request_body.nuevo_estado:
            update_data["estado"] = request_body.nuevo_estado
        if request_body.whatsapp_transportista:
            update_data["whatsappCliente"] = request_body.whatsapp_transportista
        if request_body.nombre_transportista:
            update_data["nombreCliente"] = request_body.nombre_transportista

        if update_data:
            db.ordenes.update_one({"_id": obj_id}, {"$set": update_data})

        # Obtener la orden actualizada
        orden_actualizada = db.ordenes.find_one({"_id": obj_id})
        if orden_actualizada and orden_actualizada.get('_id'):
            orden_actualizada['_id'] = str(orden_actualizada['_id'])

        return OrdenDeServicio.model_validate(orden_actualizada, from_attributes=True)

    except HTTPException as e:
        raise e
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Error al actualizar la orden: {e}")

# ======================================================================
# --- INCLUIR ROUTER EN LA APLICACIÓN PRINCIPAL ---
# ======================================================================

# CAMBIO CRÍTICO: No se utiliza el argumento 'prefix'
app.include_router(router, tags=["Transporte Rural"])

# ======================================================================
# --- EJECUCIÓN CON UVICORN ---
# ======================================================================

if __name__ == "__main__":
    uvicorn.run(
        app,
        host="0.0.0.0", 
        port=8002
    )