import os
import json
from datetime import datetime
from bson import ObjectId
from bson.errors import InvalidId
from pymongo.errors import DuplicateKeyError
from fastapi import HTTPException, Query
from typing import Optional, List, Dict, Any
from app.v1.services.sequence import get_next_sequence_value_int
from pymongo import ASCENDING, DESCENDING

COLLECTION_NAME = "fleets"
VEHICLE_COLLECTION = "vehicles"

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        if isinstance(obj, ObjectId):
            return str(obj)
        return super().default(obj)



def create_fleet_service(fleet_data: dict, db) -> dict:
    fleets_collection = db[COLLECTION_NAME]
    vehicles_collection = db[VEHICLE_COLLECTION]
    
    try:
        # Validate all vehicle model IDs exist
        # if fleet_data.get("vehicles"):
        #     for vehicle in fleet_data["vehicles"]:
        #         if not vehicles_collection.find_one({"_id": ObjectId(vehicle["vehicle_model_id"])}):
        #             raise HTTPException(
        #                 status_code=400, 
        #                 detail=f"Vehicle model {vehicle['vehicle_model_id']} not found"
        #             )
        
        # Set timestamps
        current_time = datetime.utcnow()
        fleet_data["created_date"] = current_time
        fleet_data["updated_date"] = current_time

        fleet_data["fleets_id"] = get_next_sequence_value_int("fleets_id", db)
        
        # Insert the fleet
        result = fleets_collection.insert_one(fleet_data)
        fleet_id = str(result.inserted_id)
        fleet_data["_id"] = fleet_id
        fleet_data["fleet_id"] = fleet_id
        
        # Update vehicles with fleet reference
        # if fleet_data.get("vehicles"):
        #     for vehicle in fleet_data["vehicles"]:
        #         vehicles_collection.update_one(
        #             {"_id": ObjectId(vehicle["vehicle_model_id"])},
        #             {"$addToSet": {"fleet_ids": fleet_id}}
        #         )
        
        # Convert datetime fields to ISO strings
        for field in ["created_date", "updated_date"]:
            if field in fleet_data and isinstance(fleet_data[field], datetime):
                fleet_data[field] = fleet_data[field].isoformat()
        
        # Ensure all vehicle fields are preserved in the response
        if "vehicles" in fleet_data:
            for vehicle in fleet_data["vehicles"]:
                # Preserve vehicle_type if it exists
                if "vehicle_type" not in vehicle:
                    model = vehicles_collection.find_one({"_id": ObjectId(vehicle["vehicle_model_id"])})
                    if model:
                        vehicle["vehicle_type"] = model.get("vehicle_type", "")
                
                # Preserve model_details if it exists
                if "model_details" not in vehicle:
                    model = vehicles_collection.find_one({"_id": ObjectId(vehicle["vehicle_model_id"])})
                    if model:
                        vehicle["model_details"] = {
                            "manufacturer_name": model.get("manufacturer_name", ""),
                            "vehicle_type": model.get("vehicle_type", ""),
                            "fuel_type": model.get("fuel_type", "")
                        }
        
        # Return the response in the format the endpoint expects
        return {
            "fleet_data": fleet_data  # Changed to match what the endpoint expects
        }
    except DuplicateKeyError:
        raise HTTPException(status_code=400, detail="Fleet creation failed")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Server error: {str(e)}")




def get_fleets_service(
    account_id: str,
    skip: int,
    limit: int,
    q: Optional[str],
    status: Optional[str],
    created_date_from: Optional[str],
    created_date_to: Optional[str],
    sort_by: Optional[str],
    sort_order: Optional[str],
    db
) -> dict:
    fleets_collection = db[COLLECTION_NAME]
    vehicle_models_collection = db[VEHICLE_COLLECTION]
    query = {}

    if account_id != "all":
        query["account_id"] = account_id

    if q:
        regex_query = {"$regex": q, "$options": "i"}
        query["$or"] = [
            {"fleet_name": regex_query},
            {"description": regex_query},
            {"registration_number": regex_query},
            {"vin_number": regex_query}
        ]

    if status:
        query["status"] = status

    # Add date range filter
    if created_date_from or created_date_to:
        date_filter = {}
        if created_date_from:
            date_filter["$gte"] = datetime.strptime(created_date_from, "%Y-%m-%d")
        if created_date_to:
            date_filter["$lte"] = datetime.strptime(created_date_to, "%Y-%m-%d")
        query["created_date"] = date_filter

    # Sorting logic
    sort_fields = {
        "fleet_name": "fleet_name",
        "vehicle_type": "vehicle_type",
        "color": "color",
        "year": "year",
        "registration_number": "registration_number",
        "vendor_name": "vendor_name",
        "status": "status",
        "created_date": "created_date"
    }
    sort_field = sort_fields.get(sort_by, "created_date")
    sort_direction = ASCENDING if sort_order == "asc" else DESCENDING

    cursor = fleets_collection.find(query).sort(sort_field, sort_direction).skip(skip).limit(limit)
    fleets = list(cursor)
    
    formatted_fleets = []

    for fleet in fleets:
        try:
            fleet["fleet_id"] = str(fleet["_id"])
            fleet["_id"] = str(fleet["_id"])
            fleet.setdefault("account_id", "")
            fleet.setdefault("user_id", "")
            for field in ["created_date", "updated_date"]:
                if field in fleet and isinstance(fleet[field], datetime):
                    fleet[field] = fleet[field].isoformat()
            formatted_fleets.append(fleet)
        except Exception as e:
            print(f"Error processing fleet: {str(e)}")
            continue

    total_count = fleets_collection.count_documents(query)
    return {"total_count": total_count, "fleets": formatted_fleets}

# def read_fleet_service(fleet_id: str, db) -> dict:
#     fleets_collection = db[COLLECTION_NAME]
#     vehicles_collection = db[VEHICLE_COLLECTION]
    
#     try:
#         fleet_object_id = ObjectId(fleet_id)
#     except InvalidId:
#         raise HTTPException(status_code=400, detail="Invalid fleet ID")

#     fleet = fleets_collection.find_one({"_id": fleet_object_id})
#     if not fleet:
#         raise HTTPException(status_code=404, detail="Fleet not found")

#     try:
#         # Convert ObjectIds to strings
#         fleet["fleet_id"] = str(fleet["_id"])
#         fleet["_id"] = str(fleet["_id"])
        
#         # Set default values
#         fleet.setdefault("account_id", "")
#         fleet.setdefault("user_id", "")
#         fleet.setdefault("vehicles", [])
        
#         # Convert datetime fields
#         for field in ["created_date", "updated_date"]:
#             if field in fleet and isinstance(fleet[field], datetime):
#                 fleet[field] = fleet[field].isoformat()
        
#         # Process vehicles
#         for vehicle in fleet.get("vehicles", []):
#             if "vehicle_model_id" not in vehicle:
#                 continue
                
#             try:
#                 vehicle["vehicle_model_id"] = str(vehicle["vehicle_model_id"])
                
#                 model = vehicles_collection.find_one(
#                     {"_id": ObjectId(vehicle["vehicle_model_id"])},
#                     {"manufacturer_name": 1, "vehicle_type": 1, "fuel_type": 1}
#                 )
                
#                 if model:
#                     vehicle["model_details"] = {
#                         "manufacturer_name": model.get("manufacturer_name", ""),
#                         "vehicle_type": model.get("vehicle_type", ""),
#                         "fuel_type": model.get("fuel_type", "")
#                     }
#                     if "vehicle_type" not in vehicle:
#                         vehicle["vehicle_type"] = model.get("vehicle_type", "")
#                 else:
#                     vehicle["model_details"] = {
#                         "manufacturer_name": "Unknown",
#                         "vehicle_type": "Unknown",
#                         "fuel_type": "Unknown"
#                     }
                    
#             except Exception as e:
#                 print(f"Error processing vehicle in fleet {fleet_id}: {str(e)}")
#                 vehicle["model_details"] = {
#                     "manufacturer_name": "Error",
#                     "vehicle_type": "Error",
#                     "fuel_type": "Error"
#                 }
                
#     except Exception as e:
#         print(f"Error processing fleet {fleet_id}: {str(e)}")
#         raise HTTPException(status_code=500, detail="Error processing fleet data")

#     return fleet

def read_fleet_service(fleet_id: str, db) -> dict:
    fleets_collection = db[COLLECTION_NAME]
    vehicles_collection = db[VEHICLE_COLLECTION]
    
    try:
        fleet_object_id = ObjectId(fleet_id)
    except InvalidId:
        raise HTTPException(status_code=400, detail="Invalid fleet ID")

    fleet = fleets_collection.find_one({"_id": fleet_object_id})
    if not fleet:
        raise HTTPException(status_code=404, detail="Fleet not found")

    try:
        # Convert ObjectIds to strings
        fleet["fleet_id"] = str(fleet["_id"])
        fleet["_id"] = str(fleet["_id"])
        
        # Set default values
        fleet.setdefault("account_id", "")
        fleet.setdefault("user_id", "")
        fleet.setdefault("vehicles", [])
        
        # Convert datetime fields
        for field in ["created_date", "updated_date"]:
            if field in fleet and isinstance(fleet[field], datetime):
                fleet[field] = fleet[field].isoformat()
        
        # Add base URL to vehicle_image if it exists
        if "vehicle_image" in fleet and fleet["vehicle_image"]:
            # Assuming your base URL is stored in settings or environment variable
            base_url = os.getenv("BASE_URL", "http://localhost:8003")  # Default fallback
            fleet["vehicle_image"] = f"{base_url}/{fleet['vehicle_image']}"
        
        # Process vehicles
        for vehicle in fleet.get("vehicles", []):
            if "vehicle_model_id" not in vehicle:
                continue
                
            try:
                vehicle["vehicle_model_id"] = str(vehicle["vehicle_model_id"])
                
                model = vehicles_collection.find_one(
                    {"_id": ObjectId(vehicle["vehicle_model_id"])},
                    {"manufacturer_name": 1, "vehicle_type": 1, "fuel_type": 1}
                )
                
                if model:
                    vehicle["model_details"] = {
                        "manufacturer_name": model.get("manufacturer_name", ""),
                        "vehicle_type": model.get("vehicle_type", ""),
                        "fuel_type": model.get("fuel_type", "")
                    }
                    if "vehicle_type" not in vehicle:
                        vehicle["vehicle_type"] = model.get("vehicle_type", "")
                else:
                    vehicle["model_details"] = {
                        "manufacturer_name": "Unknown",
                        "vehicle_type": "Unknown",
                        "fuel_type": "Unknown"
                    }
                    
            except Exception as e:
                print(f"Error processing vehicle in fleet {fleet_id}: {str(e)}")
                vehicle["model_details"] = {
                    "manufacturer_name": "Error",
                    "vehicle_type": "Error",
                    "fuel_type": "Error"
                }
                
    except Exception as e:
        print(f"Error processing fleet {fleet_id}: {str(e)}")
        raise HTTPException(status_code=500, detail="Error processing fleet data")

    return fleet

def update_fleet_service(fleet_id: str, fleet_data: dict, db) -> dict:
    fleets_collection = db[COLLECTION_NAME]
    vehicles_collection = db[VEHICLE_COLLECTION]
    
    try:
        fleet_object_id = ObjectId(fleet_id)
    except InvalidId:
        raise HTTPException(status_code=400, detail="Invalid fleet ID")

    existing_fleet = fleets_collection.find_one({"_id": fleet_object_id})
    if not existing_fleet:
        raise HTTPException(status_code=404, detail="Fleet not found")

    update_data = {k: v for k, v in fleet_data.items() if v is not None}
    update_data["updated_date"] = datetime.utcnow()

    # Validate vehicle model IDs if updating vehicles
    if "vehicles" in update_data:
        for vehicle in update_data["vehicles"]:
            if not vehicles_collection.find_one({"_id": ObjectId(vehicle["vehicle_model_id"])}):
                raise HTTPException(
                    status_code=400, 
                    detail=f"Vehicle model {vehicle['vehicle_model_id']} not found"
                )

    result = fleets_collection.update_one(
        {"_id": fleet_object_id},
        {"$set": update_data}
    )
    
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Fleet not found")

    updated_fleet = fleets_collection.find_one({"_id": fleet_object_id})
    
    # Convert ObjectIds to strings
    updated_fleet["fleet_id"] = str(updated_fleet["_id"])
    updated_fleet["_id"] = str(updated_fleet["_id"])
    
    # Set default values
    updated_fleet.setdefault("account_id", "")
    updated_fleet.setdefault("user_id", "")
    updated_fleet.setdefault("vehicles", [])
    
    # Convert datetime fields
    for field in ["created_date", "updated_date"]:
        if field in updated_fleet and isinstance(updated_fleet[field], datetime):
            updated_fleet[field] = updated_fleet[field].isoformat()
    
    return updated_fleet

def delete_fleet_service(fleet_id: str, db) -> dict:
    fleets_collection = db[COLLECTION_NAME]
    vehicles_collection = db[VEHICLE_COLLECTION]
    
    try:
        fleet_object_id = ObjectId(fleet_id)
    except InvalidId:
        raise HTTPException(status_code=400, detail="Invalid fleet ID")

    fleet = fleets_collection.find_one({"_id": fleet_object_id})
    if not fleet:
        raise HTTPException(status_code=404, detail="Fleet not found")

    # Remove fleet reference from all associated vehicles
    if fleet.get("vehicles"):
        for vehicle in fleet["vehicles"]:
            vehicles_collection.update_one(
                {"_id": ObjectId(vehicle["vehicle_model_id"])},
                {"$pull": {"fleet_ids": fleet_id}}
            )
    
    # Delete the fleet
    fleets_collection.delete_one({"_id": fleet_object_id})
    
    # Convert ObjectIds to strings
    fleet["fleet_id"] = str(fleet["_id"])
    fleet["_id"] = str(fleet["_id"])
    
    # Set default values
    fleet.setdefault("account_id", "")
    fleet.setdefault("user_id", "")
    fleet.setdefault("vehicles", [])
    
    # Convert datetime fields
    for field in ["created_date", "updated_date"]:
        if field in fleet and isinstance(fleet[field], datetime):
            fleet[field] = fleet[field].isoformat()
    
    return fleet

def get_fleet_vehicles_service(fleet_id: str, db) -> List[Dict[str, Any]]:
    fleets_collection = db[COLLECTION_NAME]
    vehicles_collection = db[VEHICLE_COLLECTION]
    
    try:
        fleet_object_id = ObjectId(fleet_id)
    except InvalidId:
        raise HTTPException(status_code=400, detail="Invalid fleet ID")

    fleet = fleets_collection.find_one({"_id": fleet_object_id})
    if not fleet:
        raise HTTPException(status_code=404, detail="Fleet not found")

    vehicles = []
    for vehicle in fleet.get("vehicles", []):
        # Get vehicle model details
        model = vehicles_collection.find_one({"_id": ObjectId(vehicle["vehicle_model_id"])})
        if model:
            vehicle_data = {
                **vehicle,
                "model_details": {
                    "manufacturer_name": model.get("manufacturer_name", ""),
                    "vehicle_type": model.get("vehicle_type", ""),
                    "fuel_type": model.get("fuel_type", ""),
                    "is_autonomous": model.get("is_autonomous", False),
                    "can_fly": model.get("can_fly", False)
                }
            }
            vehicles.append(vehicle_data)
    
    return vehicles

def get_fleet_dropdown_list(db, account_id: str, query: str = "", all: str = "") -> List[Dict[str, str]]:
    fleets_collection = db[COLLECTION_NAME]

    # Default filter: by account
    filters = {"account_id": account_id}

    if all != "all":
        filters["is_fleet_assigned"] = {"$ne": True}

    if query:
        filters["fleet_name"] = {"$regex": re.escape(query), "$options": "i"}

    fleets = fleets_collection.find(filters, {"fleet_name": 1})
    return [{"id": str(f["_id"]), "fleet_name": f.get("fleet_name", "")} for f in fleets]

