from fastapi import FastAPI, APIRouter, HTTPException, Depends, UploadFile, File
from fastapi.responses import FileResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from dotenv import load_dotenv
from starlette.middleware.cors import CORSMiddleware
from motor.motor_asyncio import AsyncIOMotorClient
import os
import logging
import uuid
import httpx
from pathlib import Path
from pydantic import BaseModel, Field, ConfigDict
from typing import List, Optional
from datetime import datetime, timezone
from passlib.context import CryptContext
import jwt
from fastapi import Request as FastAPIRequest
from emergentintegrations.payments.stripe.checkout import StripeCheckout, CheckoutSessionResponse, CheckoutStatusResponse, CheckoutSessionRequest

ROOT_DIR = Path(__file__).parent
load_dotenv(ROOT_DIR / '.env')

# MongoDB
mongo_url = os.environ['MONGO_URL']
client = AsyncIOMotorClient(mongo_url)
db = client[os.environ['DB_NAME']]

# JWT Config
JWT_SECRET = os.environ.get('JWT_SECRET', 'default-secret-change-me')
JWT_ALGORITHM = "HS256"

# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Upload directory
UPLOAD_DIR = ROOT_DIR / "uploads"
UPLOAD_DIR.mkdir(exist_ok=True)

app = FastAPI()
api_router = APIRouter(prefix="/api")
security = HTTPBearer()

# --- Pydantic Models ---
class AdminLogin(BaseModel):
    username: str
    password: str

class PartRequestCreate(BaseModel):
    vehicle_year: Optional[str] = ""
    make: Optional[str] = ""
    model: Optional[str] = ""
    engine: Optional[str] = ""
    part_needed: str
    vin: Optional[str] = ""
    budget: Optional[str] = ""
    photo_url: Optional[str] = ""
    name: str
    email: str
    phone: Optional[str] = ""
    notes: Optional[str] = ""

class PartRequestUpdate(BaseModel):
    status: Optional[str] = None
    quoted_price: Optional[float] = None
    cost_price: Optional[float] = None
    notes: Optional[str] = None

class InventoryItemCreate(BaseModel):
    name: str
    description: Optional[str] = ""
    price: float
    original_price: Optional[float] = None
    vehicle_year: Optional[str] = ""
    make: Optional[str] = ""
    model: Optional[str] = ""
    category: Optional[str] = ""
    condition: Optional[str] = "Used - Good"
    image_url: Optional[str] = ""
    source: Optional[str] = ""
    location: Optional[str] = ""
    shipping_days: Optional[str] = ""
    in_stock: bool = True

class ContactCreate(BaseModel):
    name: str
    email: str
    phone: Optional[str] = ""
    message: str

class UserRegister(BaseModel):
    name: str
    email: str
    password: str
    phone: Optional[str] = ""

class UserLoginModel(BaseModel):
    email: str
    password: str

class QuoteCreate(BaseModel):
    request_id: str
    items: List[dict] = []
    total: float
    notes: Optional[str] = ""
    estimated_shipping: Optional[str] = ""

class QuoteAction(BaseModel):
    action: str

class OrderStatusUpdate(BaseModel):
    status: str

class InvoiceCreate(BaseModel):
    order_id: str
    amount: float
    due_date: Optional[str] = ""
    notes: Optional[str] = ""

class ShipmentCreate(BaseModel):
    order_id: str
    carrier: str
    tracking_number: str
    estimated_delivery: Optional[str] = ""
    status: Optional[str] = "in_transit"

class VehicleCreate(BaseModel):
    year: str
    make: str
    model: str
    vin: Optional[str] = ""
    engine: Optional[str] = ""
    trim: Optional[str] = ""
    nickname: Optional[str] = ""

class VehicleUpdate(BaseModel):
    year: Optional[str] = None
    make: Optional[str] = None
    model: Optional[str] = None
    vin: Optional[str] = None
    engine: Optional[str] = None
    trim: Optional[str] = None
    nickname: Optional[str] = None

class PayInvoiceRequest(BaseModel):
    invoice_id: str
    origin_url: str

class SourcingNoteCreate(BaseModel):
    title: str
    content: str
    category: Optional[str] = "general"
    source_url: Optional[str] = ""

# --- Auth Helpers ---
def create_token(data: dict):
    return jwt.encode(data, JWT_SECRET, algorithm=JWT_ALGORITHM)

def verify_token(token: str):
    try:
        return jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
    except Exception:
        return None

async def get_current_admin(credentials: HTTPAuthorizationCredentials = Depends(security)):
    payload = verify_token(credentials.credentials)
    if not payload or payload.get("role") != "admin":
        raise HTTPException(status_code=401, detail="Invalid admin token")
    return payload

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    payload = verify_token(credentials.credentials)
    if not payload or payload.get("role") != "user":
        raise HTTPException(status_code=401, detail="Invalid user token")
    return payload

# --- Auth Routes ---
@api_router.post("/auth/login")
async def login(data: AdminLogin):
    admin = await db.admins.find_one({"username": data.username}, {"_id": 0})
    if not admin or not pwd_context.verify(data.password, admin["password_hash"]):
        raise HTTPException(status_code=401, detail="Invalid credentials")
    token = create_token({"sub": admin["username"], "id": admin["id"], "role": "admin"})
    return {"token": token, "username": admin["username"], "role": "admin"}

@api_router.get("/auth/me")
async def get_me(admin=Depends(get_current_admin)):
    return {"username": admin["sub"], "id": admin["id"], "role": "admin"}

# --- User Auth ---
@api_router.post("/user/register")
async def register_user(data: UserRegister):
    existing = await db.users.find_one({"email": data.email})
    if existing:
        raise HTTPException(status_code=400, detail="Email already registered")
    doc = {
        "id": str(uuid.uuid4()),
        "name": data.name,
        "email": data.email,
        "password_hash": pwd_context.hash(data.password),
        "phone": data.phone,
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.users.insert_one(doc)
    token = create_token({"sub": doc["email"], "id": doc["id"], "name": doc["name"], "role": "user"})
    return {"token": token, "user": {"id": doc["id"], "name": doc["name"], "email": doc["email"]}}

@api_router.post("/user/login")
async def user_login(data: UserLoginModel):
    user = await db.users.find_one({"email": data.email}, {"_id": 0})
    if not user or not pwd_context.verify(data.password, user["password_hash"]):
        raise HTTPException(status_code=401, detail="Invalid credentials")
    token = create_token({"sub": user["email"], "id": user["id"], "name": user["name"], "role": "user"})
    return {"token": token, "user": {"id": user["id"], "name": user["name"], "email": user["email"]}}

@api_router.get("/user/me")
async def get_user_me(user=Depends(get_current_user)):
    u = await db.users.find_one({"id": user["id"]}, {"_id": 0, "password_hash": 0})
    if not u:
        raise HTTPException(status_code=404, detail="User not found")
    return u

# --- Part Requests ---
@api_router.post("/part-requests")
async def create_part_request(data: PartRequestCreate):
    doc = {
        "id": str(uuid.uuid4()),
        **data.model_dump(),
        "user_id": None,
        "status": "new",
        "quoted_price": None,
        "cost_price": None,
        "profit": None,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "updated_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.part_requests.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.post("/user/part-requests")
async def create_user_part_request(data: PartRequestCreate, user=Depends(get_current_user)):
    doc = {
        "id": str(uuid.uuid4()),
        **data.model_dump(),
        "user_id": user["id"],
        "user_name": user.get("name", ""),
        "status": "new",
        "quoted_price": None,
        "cost_price": None,
        "profit": None,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "updated_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.part_requests.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.get("/user/part-requests")
async def list_user_part_requests(user=Depends(get_current_user)):
    return await db.part_requests.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(100)

@api_router.get("/part-requests")
async def list_part_requests(admin=Depends(get_current_admin)):
    requests = await db.part_requests.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)
    return requests

@api_router.patch("/part-requests/{request_id}")
async def update_part_request(request_id: str, data: PartRequestUpdate, admin=Depends(get_current_admin)):
    update_data = {k: v for k, v in data.model_dump().items() if v is not None}
    update_data["updated_at"] = datetime.now(timezone.utc).isoformat()
    # Calculate profit
    if "quoted_price" in update_data or "cost_price" in update_data:
        existing = await db.part_requests.find_one({"id": request_id}, {"_id": 0})
        if existing:
            qp = update_data.get("quoted_price", existing.get("quoted_price"))
            cp = update_data.get("cost_price", existing.get("cost_price"))
            if qp is not None and cp is not None:
                update_data["profit"] = qp - cp
    result = await db.part_requests.update_one({"id": request_id}, {"$set": update_data})
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Request not found")
    updated = await db.part_requests.find_one({"id": request_id}, {"_id": 0})
    return updated

@api_router.delete("/part-requests/{request_id}")
async def delete_part_request(request_id: str, admin=Depends(get_current_admin)):
    result = await db.part_requests.delete_one({"id": request_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Request not found")
    return {"message": "Deleted"}

# --- Inventory ---
@api_router.get("/inventory")
async def list_inventory():
    items = await db.inventory.find({}, {"_id": 0}).sort("created_at", -1).to_list(100)
    return items

@api_router.post("/inventory")
async def create_inventory_item(data: InventoryItemCreate, admin=Depends(get_current_admin)):
    doc = {
        "id": str(uuid.uuid4()),
        **data.model_dump(),
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.inventory.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.delete("/inventory/{item_id}")
async def delete_inventory_item(item_id: str, admin=Depends(get_current_admin)):
    result = await db.inventory.delete_one({"id": item_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"message": "Deleted"}

# --- Contacts ---
@api_router.post("/contact")
async def create_contact(data: ContactCreate):
    doc = {
        "id": str(uuid.uuid4()),
        **data.model_dump(),
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.contact_submissions.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.get("/contacts")
async def list_contacts(admin=Depends(get_current_admin)):
    contacts = await db.contact_submissions.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)
    return contacts

# --- Testimonials ---
@api_router.get("/testimonials")
async def list_testimonials():
    testimonials = await db.testimonials.find({}, {"_id": 0}).to_list(50)
    return testimonials

# --- Dashboard Stats ---
@api_router.get("/dashboard/stats")
async def get_dashboard_stats(admin=Depends(get_current_admin)):
    total = await db.part_requests.count_documents({})
    new_count = await db.part_requests.count_documents({"status": "new"})
    in_progress = await db.part_requests.count_documents({"status": "in_progress"})
    completed = await db.part_requests.count_documents({"status": "completed"})
    pipeline = [
        {"$match": {"status": "completed", "quoted_price": {"$ne": None}}},
        {"$group": {"_id": None, "total_revenue": {"$sum": "$quoted_price"}, "total_profit": {"$sum": "$profit"}}}
    ]
    agg_result = await db.part_requests.aggregate(pipeline).to_list(1)
    revenue = agg_result[0]["total_revenue"] if agg_result else 0
    profit = agg_result[0]["total_profit"] if agg_result else 0
    contacts_count = await db.contact_submissions.count_documents({})
    orders_count = await db.orders.count_documents({})
    quotes_count = await db.quotes.count_documents({})
    customers_count = await db.users.count_documents({})
    unpaid_invoices = await db.invoices.count_documents({"status": "unpaid"})
    paid_invoices = await db.invoices.count_documents({"status": "paid"})
    inv_pipeline = [{"$match": {"status": "paid"}}, {"$group": {"_id": None, "total": {"$sum": "$amount"}}}]
    inv_agg = await db.invoices.aggregate(inv_pipeline).to_list(1)
    total_collected = inv_agg[0]["total"] if inv_agg else 0
    return {
        "total_requests": total,
        "new_requests": new_count,
        "in_progress": in_progress,
        "completed": completed,
        "total_revenue": revenue or 0,
        "total_profit": profit or 0,
        "total_contacts": contacts_count,
        "total_orders": orders_count,
        "total_quotes": quotes_count,
        "total_customers": customers_count,
        "unpaid_invoices": unpaid_invoices,
        "paid_invoices": paid_invoices,
        "total_collected": total_collected or 0,
    }

# --- Admin: Customer Management ---
@api_router.get("/admin/customers")
async def list_customers(admin=Depends(get_current_admin)):
    customers = await db.users.find({}, {"_id": 0, "password_hash": 0}).sort("created_at", -1).to_list(1000)
    # Enrich with counts
    for c in customers:
        uid = c["id"]
        c["requests_count"] = await db.part_requests.count_documents({"user_id": uid})
        c["orders_count"] = await db.orders.count_documents({"user_id": uid})
        c["invoices_total"] = 0
        inv_agg = await db.invoices.aggregate([{"$match": {"user_id": uid}}, {"$group": {"_id": None, "total": {"$sum": "$amount"}}}]).to_list(1)
        if inv_agg:
            c["invoices_total"] = inv_agg[0]["total"]
        c["unpaid_amount"] = 0
        unpaid_agg = await db.invoices.aggregate([{"$match": {"user_id": uid, "status": "unpaid"}}, {"$group": {"_id": None, "total": {"$sum": "$amount"}}}]).to_list(1)
        if unpaid_agg:
            c["unpaid_amount"] = unpaid_agg[0]["total"]
    return customers

@api_router.get("/admin/customers/{customer_id}")
async def get_customer_profile(customer_id: str, admin=Depends(get_current_admin)):
    user = await db.users.find_one({"id": customer_id}, {"_id": 0, "password_hash": 0})
    if not user:
        raise HTTPException(status_code=404, detail="Customer not found")
    uid = customer_id
    user["vehicles"] = await db.vehicles.find({"user_id": uid}, {"_id": 0}).to_list(50)
    user["requests"] = await db.part_requests.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(100)
    user["quotes"] = await db.quotes.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(100)
    user["orders"] = await db.orders.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(100)
    user["invoices"] = await db.invoices.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(100)
    user["shipments"] = await db.shipments.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(100)
    user["payments"] = await db.payment_transactions.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(100)
    return user

# --- Admin: Pipeline Stage Update ---
@api_router.patch("/admin/pipeline/{request_id}")
async def update_pipeline_stage(request_id: str, data: dict, admin=Depends(get_current_admin)):
    stage = data.get("pipeline_stage")
    if not stage:
        raise HTTPException(status_code=400, detail="pipeline_stage required")
    result = await db.part_requests.update_one(
        {"id": request_id},
        {"$set": {"pipeline_stage": stage, "updated_at": datetime.now(timezone.utc).isoformat()}}
    )
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Request not found")
    return await db.part_requests.find_one({"id": request_id}, {"_id": 0})

# --- Admin: Pipeline View ---
@api_router.get("/admin/pipeline")
async def get_pipeline(admin=Depends(get_current_admin)):
    """Get all requests grouped by pipeline stage."""
    requests = await db.part_requests.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)
    stages = ["new_lead", "vin_review", "sourcing", "quote_sent", "invoice_sent", "paid", "ordered", "shipped", "delivered"]
    # Map old statuses to pipeline stages
    stage_map = {"new": "new_lead", "quoted": "quote_sent", "in_progress": "sourcing", "completed": "delivered"}
    pipeline = {stage: [] for stage in stages}
    for req in requests:
        stage = req.get("pipeline_stage") or stage_map.get(req.get("status", "new"), "new_lead")
        if stage in pipeline:
            pipeline[stage].append(req)
        else:
            pipeline["new_lead"].append(req)
    return pipeline

# --- VIN Decoder ---
@api_router.get("/vin-decode/{vin}")
async def decode_vin(vin: str):
    if len(vin) != 17:
        raise HTTPException(status_code=400, detail="VIN must be 17 characters")
    async with httpx.AsyncClient() as http_client:
        try:
            resp = await http_client.get(
                f"https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVinValues/{vin}?format=json",
                timeout=10
            )
            data = resp.json()
            results = data.get("Results", [{}])[0]
            engine_parts = [p for p in [results.get("DisplacementL", ""), results.get("EngineCylinders", ""), results.get("FuelTypePrimary", "")] if p]
            engine_str = "L ".join(engine_parts[:1]) + " " + " ".join(engine_parts[1:]) if engine_parts else ""
            return {
                "year": results.get("ModelYear", ""),
                "make": results.get("Make", ""),
                "model": results.get("Model", ""),
                "engine": engine_str.strip(),
                "body_class": results.get("BodyClass", ""),
                "drive_type": results.get("DriveType", ""),
                "transmission": results.get("TransmissionStyle", ""),
            }
        except Exception as e:
            raise HTTPException(status_code=400, detail=f"VIN decode failed: {str(e)}")

# --- File Upload ---
@api_router.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    allowed = {"image/jpeg", "image/png", "image/webp", "image/gif"}
    if file.content_type not in allowed:
        raise HTTPException(status_code=400, detail="Invalid file type. Only images allowed.")
    contents = await file.read()
    if len(contents) > 10 * 1024 * 1024:
        raise HTTPException(status_code=400, detail="File too large. Max 10MB.")
    ext = file.filename.split(".")[-1] if file.filename and "." in file.filename else "jpg"
    filename = f"{uuid.uuid4()}.{ext}"
    filepath = UPLOAD_DIR / filename
    with open(filepath, "wb") as f:
        f.write(contents)
    return {"url": f"/api/uploads/{filename}", "filename": filename}

@api_router.get("/uploads/{filename}")
async def get_upload(filename: str):
    filepath = UPLOAD_DIR / filename
    if not filepath.exists():
        raise HTTPException(status_code=404, detail="File not found")
    return FileResponse(filepath)

# --- Quotes ---
@api_router.post("/quotes")
async def create_quote(data: QuoteCreate, admin=Depends(get_current_admin)):
    request = await db.part_requests.find_one({"id": data.request_id}, {"_id": 0})
    if not request:
        raise HTTPException(status_code=404, detail="Request not found")
    doc = {
        "id": str(uuid.uuid4()),
        "request_id": data.request_id,
        "user_id": request.get("user_id"),
        "vehicle_info": f"{request.get('vehicle_year','')} {request.get('make','')} {request.get('model','')}".strip(),
        "part_needed": request.get("part_needed", ""),
        "items": data.items,
        "total": data.total,
        "notes": data.notes,
        "estimated_shipping": data.estimated_shipping,
        "status": "pending",
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.quotes.insert_one(doc)
    doc.pop("_id", None)
    await db.part_requests.update_one(
        {"id": data.request_id},
        {"$set": {"status": "quoted", "quoted_price": data.total, "updated_at": datetime.now(timezone.utc).isoformat()}}
    )
    return doc

@api_router.get("/quotes")
async def list_all_quotes(admin=Depends(get_current_admin)):
    return await db.quotes.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)

@api_router.get("/user/quotes")
async def list_user_quotes(user=Depends(get_current_user)):
    return await db.quotes.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(100)

@api_router.post("/user/quotes/{quote_id}/action")
async def user_quote_action(quote_id: str, data: QuoteAction, user=Depends(get_current_user)):
    quote = await db.quotes.find_one({"id": quote_id, "user_id": user["id"]}, {"_id": 0})
    if not quote:
        raise HTTPException(status_code=404, detail="Quote not found")
    if quote["status"] != "pending":
        raise HTTPException(status_code=400, detail="Quote already actioned")
    if data.action == "approve":
        await db.quotes.update_one({"id": quote_id}, {"$set": {"status": "approved"}})
        order = {
            "id": str(uuid.uuid4()),
            "order_number": f"ORD-{str(uuid.uuid4())[:8].upper()}",
            "quote_id": quote_id,
            "request_id": quote["request_id"],
            "user_id": user["id"],
            "total": quote["total"],
            "items": quote["items"],
            "vehicle_info": quote.get("vehicle_info", ""),
            "part_needed": quote.get("part_needed", ""),
            "status": "processing",
            "created_at": datetime.now(timezone.utc).isoformat(),
            "updated_at": datetime.now(timezone.utc).isoformat(),
        }
        await db.orders.insert_one(order)
        order.pop("_id", None)
        await db.part_requests.update_one({"id": quote["request_id"]}, {"$set": {"status": "in_progress", "updated_at": datetime.now(timezone.utc).isoformat()}})
        return {"message": "Quote approved, order created", "order": order}
    elif data.action == "reject":
        await db.quotes.update_one({"id": quote_id}, {"$set": {"status": "rejected"}})
        await db.part_requests.update_one({"id": quote["request_id"]}, {"$set": {"status": "new", "updated_at": datetime.now(timezone.utc).isoformat()}})
        return {"message": "Quote rejected"}
    raise HTTPException(status_code=400, detail="Invalid action. Use 'approve' or 'reject'.")

# --- Orders ---
@api_router.get("/orders")
async def list_all_orders(admin=Depends(get_current_admin)):
    return await db.orders.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)

@api_router.get("/user/orders")
async def list_user_orders(user=Depends(get_current_user)):
    return await db.orders.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(100)

@api_router.patch("/orders/{order_id}")
async def update_order_status(order_id: str, data: OrderStatusUpdate, admin=Depends(get_current_admin)):
    result = await db.orders.update_one({"id": order_id}, {"$set": {"status": data.status, "updated_at": datetime.now(timezone.utc).isoformat()}})
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Order not found")
    if data.status == "delivered":
        order = await db.orders.find_one({"id": order_id}, {"_id": 0})
        if order:
            await db.part_requests.update_one({"id": order["request_id"]}, {"$set": {"status": "completed", "updated_at": datetime.now(timezone.utc).isoformat()}})
    return await db.orders.find_one({"id": order_id}, {"_id": 0})

# --- Invoices ---
@api_router.post("/invoices")
async def create_invoice(data: InvoiceCreate, admin=Depends(get_current_admin)):
    order = await db.orders.find_one({"id": data.order_id}, {"_id": 0})
    if not order:
        raise HTTPException(status_code=404, detail="Order not found")
    doc = {
        "id": str(uuid.uuid4()),
        "invoice_number": f"INV-{str(uuid.uuid4())[:8].upper()}",
        "order_id": data.order_id,
        "order_number": order.get("order_number", ""),
        "request_id": order.get("request_id"),
        "user_id": order.get("user_id"),
        "amount": data.amount,
        "vehicle_info": order.get("vehicle_info", ""),
        "part_needed": order.get("part_needed", ""),
        "due_date": data.due_date,
        "notes": data.notes,
        "status": "unpaid",
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.invoices.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.get("/invoices")
async def list_all_invoices(admin=Depends(get_current_admin)):
    return await db.invoices.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)

@api_router.get("/user/invoices")
async def list_user_invoices(user=Depends(get_current_user)):
    return await db.invoices.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(100)

@api_router.patch("/invoices/{invoice_id}/pay")
async def mark_invoice_paid(invoice_id: str, admin=Depends(get_current_admin)):
    result = await db.invoices.update_one({"id": invoice_id}, {"$set": {"status": "paid", "paid_at": datetime.now(timezone.utc).isoformat()}})
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Invoice not found")
    return await db.invoices.find_one({"id": invoice_id}, {"_id": 0})

# --- Shipments ---
@api_router.post("/shipments")
async def create_shipment(data: ShipmentCreate, admin=Depends(get_current_admin)):
    order = await db.orders.find_one({"id": data.order_id}, {"_id": 0})
    if not order:
        raise HTTPException(status_code=404, detail="Order not found")
    doc = {
        "id": str(uuid.uuid4()),
        "order_id": data.order_id,
        "order_number": order.get("order_number", ""),
        "request_id": order.get("request_id"),
        "user_id": order.get("user_id"),
        "vehicle_info": order.get("vehicle_info", ""),
        "part_needed": order.get("part_needed", ""),
        "carrier": data.carrier,
        "tracking_number": data.tracking_number,
        "estimated_delivery": data.estimated_delivery,
        "status": data.status or "in_transit",
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.shipments.insert_one(doc)
    doc.pop("_id", None)
    await db.orders.update_one({"id": data.order_id}, {"$set": {"status": "shipped", "updated_at": datetime.now(timezone.utc).isoformat()}})
    return doc

@api_router.get("/shipments")
async def list_all_shipments(admin=Depends(get_current_admin)):
    return await db.shipments.find({}, {"_id": 0}).sort("created_at", -1).to_list(1000)

@api_router.get("/user/shipments")
async def list_user_shipments(user=Depends(get_current_user)):
    return await db.shipments.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(100)

@api_router.patch("/shipments/{shipment_id}/deliver")
async def mark_shipment_delivered(shipment_id: str, admin=Depends(get_current_admin)):
    shipment = await db.shipments.find_one({"id": shipment_id}, {"_id": 0})
    if not shipment:
        raise HTTPException(status_code=404, detail="Shipment not found")
    await db.shipments.update_one({"id": shipment_id}, {"$set": {"status": "delivered"}})
    await db.orders.update_one({"id": shipment["order_id"]}, {"$set": {"status": "delivered", "updated_at": datetime.now(timezone.utc).isoformat()}})
    order = await db.orders.find_one({"id": shipment["order_id"]}, {"_id": 0})
    if order:
        await db.part_requests.update_one({"id": order["request_id"]}, {"$set": {"status": "completed", "updated_at": datetime.now(timezone.utc).isoformat()}})
    return await db.shipments.find_one({"id": shipment_id}, {"_id": 0})

# --- User Vehicles (Garage) ---
@api_router.get("/user/vehicles")
async def list_user_vehicles(user=Depends(get_current_user)):
    return await db.vehicles.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(50)

@api_router.post("/user/vehicles")
async def create_vehicle(data: VehicleCreate, user=Depends(get_current_user)):
    doc = {
        "id": str(uuid.uuid4()),
        "user_id": user["id"],
        **data.model_dump(),
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.vehicles.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.patch("/user/vehicles/{vehicle_id}")
async def update_vehicle(vehicle_id: str, data: VehicleUpdate, user=Depends(get_current_user)):
    update_data = {k: v for k, v in data.model_dump().items() if v is not None}
    if not update_data:
        raise HTTPException(status_code=400, detail="No fields to update")
    result = await db.vehicles.update_one(
        {"id": vehicle_id, "user_id": user["id"]},
        {"$set": update_data}
    )
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Vehicle not found")
    return await db.vehicles.find_one({"id": vehicle_id}, {"_id": 0})

@api_router.delete("/user/vehicles/{vehicle_id}")
async def delete_vehicle(vehicle_id: str, user=Depends(get_current_user)):
    result = await db.vehicles.delete_one({"id": vehicle_id, "user_id": user["id"]})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Vehicle not found")
    return {"message": "Vehicle removed"}

# --- User Overview Stats ---
@api_router.get("/user/overview")
async def get_user_overview(user=Depends(get_current_user)):
    uid = user["id"]
    requests = await db.part_requests.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(5)
    pending_quotes = await db.quotes.count_documents({"user_id": uid, "status": "pending"})
    active_orders = await db.orders.count_documents({"user_id": uid, "status": {"$nin": ["delivered", "cancelled"]}})
    unpaid_invoices = await db.invoices.find({"user_id": uid, "status": "unpaid"}, {"_id": 0}).to_list(100)
    unpaid_total = sum(inv.get("amount", 0) for inv in unpaid_invoices)
    vehicles = await db.vehicles.count_documents({"user_id": uid})
    recent_shipments = await db.shipments.find({"user_id": uid}, {"_id": 0}).sort("created_at", -1).to_list(3)
    return {
        "recent_requests": requests,
        "pending_quotes": pending_quotes,
        "active_orders": active_orders,
        "unpaid_invoices_count": len(unpaid_invoices),
        "unpaid_total": unpaid_total,
        "vehicles_count": vehicles,
        "recent_shipments": recent_shipments,
    }

# --- Stripe Payments ---
@api_router.post("/payments/checkout")
async def create_checkout(data: PayInvoiceRequest, http_request: FastAPIRequest, user=Depends(get_current_user)):
    invoice = await db.invoices.find_one({"id": data.invoice_id, "user_id": user["id"]}, {"_id": 0})
    if not invoice:
        raise HTTPException(status_code=404, detail="Invoice not found")
    if invoice.get("status") == "paid":
        raise HTTPException(status_code=400, detail="Invoice already paid")

    api_key = os.environ.get("STRIPE_API_KEY")
    if not api_key:
        raise HTTPException(status_code=500, detail="Payment system not configured")

    host_url = data.origin_url.rstrip("/")
    webhook_url = f"{str(http_request.base_url).rstrip('/')}/api/webhook/stripe"
    stripe_checkout = StripeCheckout(api_key=api_key, webhook_url=webhook_url)

    success_url = f"{host_url}/dashboard?payment=success&session_id={{CHECKOUT_SESSION_ID}}"
    cancel_url = f"{host_url}/dashboard?payment=cancelled"

    amount = float(invoice["amount"])
    checkout_request = CheckoutSessionRequest(
        amount=amount,
        currency="usd",
        success_url=success_url,
        cancel_url=cancel_url,
        metadata={
            "invoice_id": data.invoice_id,
            "user_id": user["id"],
            "invoice_number": invoice.get("invoice_number", ""),
        },
        payment_methods=["card"],
    )

    session: CheckoutSessionResponse = await stripe_checkout.create_checkout_session(checkout_request)

    # Create payment transaction record
    txn = {
        "id": str(uuid.uuid4()),
        "session_id": session.session_id,
        "invoice_id": data.invoice_id,
        "user_id": user["id"],
        "amount": amount,
        "currency": "usd",
        "payment_status": "pending",
        "metadata": {
            "invoice_number": invoice.get("invoice_number", ""),
        },
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.payment_transactions.insert_one(txn)

    return {"url": session.url, "session_id": session.session_id}

@api_router.get("/payments/status/{session_id}")
async def get_payment_status(session_id: str, http_request: FastAPIRequest, user=Depends(get_current_user)):
    txn = await db.payment_transactions.find_one({"session_id": session_id, "user_id": user["id"]}, {"_id": 0})
    if not txn:
        raise HTTPException(status_code=404, detail="Transaction not found")

    # If already marked paid, return immediately
    if txn.get("payment_status") == "paid":
        return {"payment_status": "paid", "invoice_id": txn["invoice_id"]}

    api_key = os.environ.get("STRIPE_API_KEY")
    webhook_url = f"{str(http_request.base_url).rstrip('/')}/api/webhook/stripe"
    stripe_checkout = StripeCheckout(api_key=api_key, webhook_url=webhook_url)

    status: CheckoutStatusResponse = await stripe_checkout.get_checkout_status(session_id)

    if status.payment_status == "paid":
        # Update transaction
        await db.payment_transactions.update_one(
            {"session_id": session_id},
            {"$set": {"payment_status": "paid", "paid_at": datetime.now(timezone.utc).isoformat()}}
        )
        # Update invoice
        await db.invoices.update_one(
            {"id": txn["invoice_id"]},
            {"$set": {"status": "paid", "paid_at": datetime.now(timezone.utc).isoformat(), "stripe_session_id": session_id}}
        )
    elif status.status == "expired":
        await db.payment_transactions.update_one(
            {"session_id": session_id},
            {"$set": {"payment_status": "expired"}}
        )

    return {"payment_status": status.payment_status, "status": status.status, "invoice_id": txn["invoice_id"]}

@api_router.post("/webhook/stripe")
async def stripe_webhook(request: FastAPIRequest):
    body = await request.body()
    sig = request.headers.get("Stripe-Signature", "")
    api_key = os.environ.get("STRIPE_API_KEY")
    webhook_url = f"{str(request.base_url).rstrip('/')}/api/webhook/stripe"
    stripe_checkout = StripeCheckout(api_key=api_key, webhook_url=webhook_url)
    try:
        event = await stripe_checkout.handle_webhook(body, sig)
        if event.payment_status == "paid" and event.session_id:
            txn = await db.payment_transactions.find_one({"session_id": event.session_id}, {"_id": 0})
            if txn and txn.get("payment_status") != "paid":
                await db.payment_transactions.update_one(
                    {"session_id": event.session_id},
                    {"$set": {"payment_status": "paid", "paid_at": datetime.now(timezone.utc).isoformat()}}
                )
                await db.invoices.update_one(
                    {"id": txn["invoice_id"]},
                    {"$set": {"status": "paid", "paid_at": datetime.now(timezone.utc).isoformat(), "stripe_session_id": event.session_id}}
                )
    except Exception as e:
        logging.error(f"Webhook error: {e}")
    return {"status": "ok"}

# --- User Payment History ---
@api_router.get("/user/payments")
async def list_user_payments(user=Depends(get_current_user)):
    return await db.payment_transactions.find({"user_id": user["id"]}, {"_id": 0}).sort("created_at", -1).to_list(100)

# --- Sourcing Notes ---
@api_router.get("/admin/sourcing-notes")
async def list_sourcing_notes(admin=Depends(get_current_admin)):
    return await db.sourcing_notes.find({}, {"_id": 0}).sort("created_at", -1).to_list(200)

@api_router.post("/admin/sourcing-notes")
async def create_sourcing_note(data: SourcingNoteCreate, admin=Depends(get_current_admin)):
    doc = {
        "id": str(uuid.uuid4()),
        **data.model_dump(),
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    await db.sourcing_notes.insert_one(doc)
    doc.pop("_id", None)
    return doc

@api_router.delete("/admin/sourcing-notes/{note_id}")
async def delete_sourcing_note(note_id: str, admin=Depends(get_current_admin)):
    result = await db.sourcing_notes.delete_one({"id": note_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Note not found")
    return {"message": "Note deleted"}

# --- Seed Data ---
async def seed_data():
    admin_exists = await db.admins.find_one({"username": "admin"})
    if not admin_exists:
        await db.admins.insert_one({
            "id": str(uuid.uuid4()),
            "username": "admin",
            "password_hash": pwd_context.hash("queencity2024"),
        })
        logger.info("Seeded admin user (admin / queencity2024)")

    inv_count = await db.inventory.count_documents({})
    if inv_count == 0:
        items = [
            {"id": str(uuid.uuid4()), "name": "BMW E46 M3 S54 Engine Assembly", "description": "Complete S54 3.2L inline-6 engine. 89k miles, compression tested.", "price": 4500, "original_price": 8900, "vehicle_year": "2004", "make": "BMW", "model": "M3", "category": "Engine", "condition": "OEM Used", "image_url": "https://images.unsplash.com/photo-1486262715619-67b85e0b08d3?w=600", "source": "Salvage Auction", "location": "Texas", "shipping_days": "4-6 days", "in_stock": True, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Honda Civic Type R Brembo Brake Kit", "description": "Front Brembo 4-piston caliper kit from 2020 FK8. Like new.", "price": 890, "original_price": 2100, "vehicle_year": "2020", "make": "Honda", "model": "Civic Type R", "category": "Brakes", "condition": "OEM Used", "image_url": "https://images.unsplash.com/photo-1558618666-fcd25c85f82e?w=600", "source": "Dealer Network", "location": "California", "shipping_days": "5-7 days", "in_stock": True, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Ford F-150 EcoBoost Turbocharger", "description": "OEM turbo from 2019 F-150 3.5L EcoBoost. 45k miles.", "price": 650, "original_price": 1800, "vehicle_year": "2019", "make": "Ford", "model": "F-150", "category": "Turbo", "condition": "OEM Used", "image_url": "https://images.unsplash.com/photo-1619642751034-765dfdf7c58e?w=600", "source": "Salvage Yard", "location": "Georgia", "shipping_days": "2-3 days", "in_stock": True, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Toyota Camry LED Headlight Assembly", "description": "Driver side LED headlight from 2021 Camry XSE. No cracks.", "price": 320, "original_price": 950, "vehicle_year": "2021", "make": "Toyota", "model": "Camry", "category": "Lighting", "condition": "OEM Used", "image_url": "https://images.unsplash.com/photo-1489824904134-891ab64532f1?w=600", "source": "Wholesaler", "location": "Ohio", "shipping_days": "3-5 days", "in_stock": True, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Chevy Silverado 6L80 Transmission", "description": "Rebuilt 6-speed auto from 2018 Silverado 1500. 30-day warranty.", "price": 1200, "original_price": 3500, "vehicle_year": "2018", "make": "Chevrolet", "model": "Silverado 1500", "category": "Transmission", "condition": "Refurbished", "image_url": "https://images.unsplash.com/photo-1530046339160-ce3e530c7d2f?w=600", "source": "Liquidation Auction", "location": "Michigan", "shipping_days": "4-6 days", "in_stock": True, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Jeep Wrangler JL Door Set", "description": "Complete 4-door set from 2022 Sahara. Freedom panels included.", "price": 1800, "original_price": 4200, "vehicle_year": "2022", "make": "Jeep", "model": "Wrangler", "category": "Body", "condition": "OEM Used", "image_url": "https://images.unsplash.com/photo-1533473359331-0135ef1b58bf?w=600", "source": "Salvage Yard", "location": "Nevada", "shipping_days": "3-5 days", "in_stock": True, "created_at": datetime.now(timezone.utc).isoformat()},
        ]
        await db.inventory.insert_many(items)
        logger.info("Seeded inventory")

    test_count = await db.testimonials.count_documents({})
    if test_count == 0:
        testimonials = [
            {"id": str(uuid.uuid4()), "name": "Marcus Johnson", "role": "Independent Mechanic", "text": "Queen City saved me over $2,000 on a transmission for my client's Silverado. Parts arrived in 3 days and the quality was spot-on.", "rating": 5, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Sarah Chen", "role": "Body Shop Owner", "text": "We source 80% of our used body panels through Queen City. The pricing is unbeatable and they always find exactly what we need.", "rating": 5, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "David Williams", "role": "Car Enthusiast", "text": "Found a mint S54 engine for my E46 M3 build at half the price I was quoted elsewhere. These guys know their stuff.", "rating": 5, "created_at": datetime.now(timezone.utc).isoformat()},
            {"id": str(uuid.uuid4()), "name": "Lisa Rodriguez", "role": "Fleet Manager", "text": "Managing a fleet of 30 vehicles, parts costs add up fast. Queen City consistently saves us 40-60% on replacement parts.", "rating": 5, "created_at": datetime.now(timezone.utc).isoformat()},
        ]
        await db.testimonials.insert_many(testimonials)
        logger.info("Seeded testimonials")

# Include router and middleware
app.include_router(api_router)

app.add_middleware(
    CORSMiddleware,
    allow_credentials=True,
    allow_origins=os.environ.get('CORS_ORIGINS', '*').split(','),
    allow_methods=["*"],
    allow_headers=["*"],
)

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

@app.on_event("startup")
async def startup():
    await seed_data()

@app.on_event("shutdown")
async def shutdown():
    client.close()
