from fastapi import FastAPI, APIRouter, HTTPException, Depends, status, Query, Response, UploadFile, File, Form, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.responses import StreamingResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from dotenv import load_dotenv
from starlette.middleware.cors import CORSMiddleware
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_, or_, desc, asc, distinct, delete
from sqlalchemy.orm import selectinload
import os
import logging
import aiofiles
import asyncio
from pathlib import Path
from pydantic import BaseModel, Field, EmailStr, ConfigDict
from typing import List, Optional, Dict, Any
import uuid
from datetime import datetime, timezone, timedelta
import bcrypt
import jwt
import io
import csv
import base64
import shutil
import smtplib
import httpx
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from contextlib import asynccontextmanager
from concurrent.futures import ThreadPoolExecutor
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, A4
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch

from database import get_db, init_db, AsyncSessionLocal
from models import (
    User, Product, Service, CartItem, Order, OrderItem, OrderStatusHistory,
    Review, Booking, Contact, InventoryLog, Category, SalesReport,
    OrderStatus, UserRole, Base, ProductImage, ServiceImage,
    AboutContent, TeamMember, CompanyValue, Media, MediaType
)
from email_service import send_verification_email, send_welcome_email
from oauth_config import oauth
from itsdangerous import URLSafeTimedSerializer

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

# Create uploads directory for images
UPLOAD_DIR = ROOT_DIR / 'uploads' / 'products'
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)

# Notification settings (from environment variables)
SMTP_HOST = os.environ.get('SMTP_HOST', 'smtp.gmail.com')
SMTP_PORT = int(os.environ.get('SMTP_PORT', 587))
SMTP_USER = os.environ.get('SMTP_USER', '')
SMTP_PASSWORD = os.environ.get('SMTP_PASSWORD', '')
ADMIN_EMAIL = os.environ.get('ADMIN_EMAIL', 'admin@prompttech.com')
ADMIN_PHONE = os.environ.get('ADMIN_PHONE', '+5016261234')  # WhatsApp number
WHATSAPP_API_URL = os.environ.get('WHATSAPP_API_URL', '')  # e.g., CallMeBot or Twilio
WHATSAPP_API_KEY = os.environ.get('WHATSAPP_API_KEY', '')

# Create media uploads directory
MEDIA_UPLOAD_DIR = ROOT_DIR / 'uploads' / 'media'
MEDIA_UPLOAD_DIR.mkdir(parents=True, exist_ok=True)

# Allowed file extensions for media
ALLOWED_IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico'}
ALLOWED_DOC_EXTENSIONS = {'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt'}
ALLOWED_VIDEO_EXTENSIONS = {'.mp4', '.webm', '.mov', '.avi'}
MAX_FILE_SIZE = 50 * 1024 * 1024  # 50MB

# JWT Configuration
SECRET_KEY = os.environ.get('JWT_SECRET', 'techzone-super-secret-key-2024-production')
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_HOURS = 24

# Token serializer for email verification
serializer = URLSafeTimedSerializer(SECRET_KEY)

# Frontend URL for email links
FRONTEND_URL = os.environ.get('FRONTEND_URL', 'http://localhost:5300')

# Thread pool for CPU-intensive operations (like bcrypt)
executor = ThreadPoolExecutor(max_workers=4)

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

# Lifespan event handler for FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
    """Initialize database with error handling and verification"""
    try:
        await init_db()
        logger.info("Database initialized successfully")
        
        # Verify database connection
        try:
            async with AsyncSessionLocal() as session:
                result = await session.execute(select(func.count(User.id)))
                user_count = result.scalar()
                logger.info(f"Database connection verified - {user_count} users found")
        except Exception as e:
            logger.error(f"Database verification failed: {e}")
            
    except Exception as e:
        logger.critical(f"Database initialization failed: {e}", exc_info=True)
    
    yield
    
    # Cleanup on shutdown (if needed)
    pass

# Create the main app with lifespan
app = FastAPI(title="TechZone API", version="2.0.0", lifespan=lifespan)

# Create a router with the /api prefix
api_router = APIRouter(prefix="/api")

security = HTTPBearer()

# ================== PYDANTIC MODELS ==================

class UserCreate(BaseModel):
    email: EmailStr
    name: str
    password: str

class UserLogin(BaseModel):
    email: EmailStr
    password: str

class TokenResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"
    user: dict

class ProductCreate(BaseModel):
    name: str
    description: str  # Now supports HTML from rich text editor
    price: float
    category: str
    image_url: str = ""  # Optional - for backwards compatibility
    stock: int = 10
    low_stock_threshold: int = 5
    brand: str = ""
    specs: dict = {}
    images: List[str] = []  # List of image URLs

class ProductUpdate(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None  # Supports HTML
    price: Optional[float] = None
    category: Optional[str] = None
    image_url: Optional[str] = None
    stock: Optional[int] = None
    low_stock_threshold: Optional[int] = None
    brand: Optional[str] = None
    specs: Optional[dict] = None
    is_active: Optional[bool] = None
    images: Optional[List[str]] = None  # List of image URLs

class CategoryCreate(BaseModel):
    name: str
    slug: Optional[str] = None
    description: Optional[str] = ""

class CategoryUpdate(BaseModel):
    name: Optional[str] = None
    slug: Optional[str] = None
    description: Optional[str] = None

class ServiceCreate(BaseModel):
    name: str
    description: str
    price: float
    duration: str
    image_url: Optional[str] = ""  # Deprecated
    category: str
    images: List[str] = []

class ServiceUpdate(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    duration: Optional[str] = None
    image_url: Optional[str] = None  # Deprecated
    category: Optional[str] = None
    images: Optional[List[str]] = None
    category: Optional[str] = None
    images: Optional[List[str]] = None
    is_active: Optional[bool] = None

class CartItemCreate(BaseModel):
    product_id: str
    quantity: int = 1

class OrderCreate(BaseModel):
    shipping_address: dict = {}
    notes: str = ""

class OrderStatusUpdate(BaseModel):
    status: str
    notes: str = ""
    tracking_number: Optional[str] = None

class ReviewCreate(BaseModel):
    product_id: Optional[str] = None
    service_id: Optional[str] = None
    rating: int
    title: str = ""
    comment: str = ""

class BookingCreate(BaseModel):
    service_id: str
    name: str
    email: EmailStr
    phone: str
    preferred_date: str
    notes: str = ""

class ContactCreate(BaseModel):
    name: str
    email: EmailStr
    subject: str
    message: str

class InventoryAdjust(BaseModel):
    quantity_change: int
    notes: str = ""

# ================== HELPERS ==================

def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

def verify_password(password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))

async def hash_password_async(password: str) -> str:
    """Async wrapper for password hashing to avoid blocking the event loop"""
    loop = asyncio.get_running_loop()
    return await loop.run_in_executor(executor, hash_password, password)

async def verify_password_async(password: str, hashed: str) -> bool:
    """Async wrapper for password verification to avoid blocking the event loop"""
    loop = asyncio.get_running_loop()
    return await loop.run_in_executor(executor, verify_password, password, hashed)

def create_access_token(data: dict) -> str:
    to_encode = data.copy()
    expire = datetime.now(timezone.utc) + timedelta(hours=ACCESS_TOKEN_EXPIRE_HOURS)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security), db: AsyncSession = Depends(get_db)):
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("sub")
        if user_id is None:
            raise HTTPException(status_code=401, detail="Invalid token")
        result = await db.execute(select(User).where(User.id == user_id))
        user = result.scalar_one_or_none()
        if user is None:
            raise HTTPException(status_code=401, detail="User not found")
        return user
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

async def get_admin_user(user: User = Depends(get_current_user)):
    """Verify user has admin role with logging"""
    if not user:
        logger.warning("Admin access attempted with no user")
        raise HTTPException(status_code=401, detail="Authentication required")
    
    if user.role != UserRole.ADMIN:
        logger.warning(f"Non-admin user {user.id} attempted admin access")
        raise HTTPException(status_code=403, detail="Admin access required")
    
    logger.debug(f"Admin access granted to user {user.id}")
    return user

async def get_optional_user(credentials: Optional[HTTPAuthorizationCredentials] = Depends(HTTPBearer(auto_error=False)), db: AsyncSession = Depends(get_db)):
    if credentials is None:
        return None
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("sub")
        if user_id:
            result = await db.execute(select(User).where(User.id == user_id))
            return result.scalar_one_or_none()
    except:
        pass
    return None

# ================== CRUD HELPERS ==================

async def _get_or_404(db: AsyncSession, model, record_id: str, error_message: str = "Record not found"):
    """Generic helper to fetch a record by ID or raise 404"""
    result = await db.execute(select(model).where(model.id == record_id))
    record = result.scalar_one_or_none()
    if not record:
        raise HTTPException(status_code=404, detail=error_message)
    return record

async def _soft_delete(db: AsyncSession, record, commit: bool = True):
    """Generic helper for soft delete (set is_active=False)"""
    record.is_active = False
    if commit:
        await db.commit()
    return {"message": f"{record.__class__.__name__} deleted"}

def _build_response(message: str, **kwargs):
    """Build standardized API response"""
    response = {"message": message}
    response.update(kwargs)
    return response

# ================== SERIALIZATION HELPERS ==================

def _safe_isoformat(dt) -> Optional[str]:
    """Safely convert datetime to ISO format"""
    return dt.isoformat() if dt else None

def _safe_enum_value(enum_val, default="pending") -> str:
    """Safely extract enum value"""
    return enum_val.value if enum_val else default

def _calculate_reviews_stats(reviews: list) -> dict:
    """Calculate review statistics"""
    if not reviews:
        return {"average_rating": 0, "review_count": 0}
    return {
        "average_rating": sum(r.rating for r in reviews) / len(reviews),
        "review_count": len(reviews)
    }

def user_to_dict(user: User) -> dict:
    return {
        "id": user.id,
        "email": user.email,
        "name": user.name,
        "role": _safe_enum_value(user.role, "user"),
        "is_active": getattr(user, 'is_active', True),
        "created_at": _safe_isoformat(user.created_at)
    }

def product_to_dict(product: Product, include_reviews: bool = False) -> dict:
    # Get images if available
    images = []
    if hasattr(product, 'images') and product.images:
        images = [
            {
                "id": img.id,
                "url": img.image_url,
                "display_order": img.display_order,
                "is_primary": img.is_primary
            }
            for img in sorted(product.images, key=lambda x: x.display_order)
        ]
    
    data = {
        "id": product.id,
        "name": product.name,
        "description": product.description,  # Contains HTML from rich text editor
        "price": product.price,
        "category": product.category,
        "image_url": product.image_url or (images[0]["url"] if images else ""),  # Fallback to first image
        "images": images,  # New: array of all images
        "stock": product.stock,
        "low_stock_threshold": product.low_stock_threshold,
        "brand": product.brand,
        "specs": product.specs or {},
        "is_active": product.is_active,
        "created_at": _safe_isoformat(product.created_at)
    }
    if include_reviews and product.reviews:
        data["reviews"] = [review_to_dict(r) for r in product.reviews]
        data.update(_calculate_reviews_stats(product.reviews))
    return data

def service_to_dict(service: Service, include_reviews: bool = False) -> dict:
    # Get images if available
    images = []
    if hasattr(service, 'images') and service.images:
        images = [
            {
                "id": img.id,
                "url": img.image_url,
                "display_order": img.display_order,
                "is_primary": img.is_primary
            }
            for img in sorted(service.images, key=lambda x: x.display_order)
        ]
    
    # Set primary image_url for backwards compatibility
    primary_image = images[0]["url"] if images else service.image_url
    
    data = {
        "id": service.id,
        "name": service.name,
        "description": service.description,
        "price": service.price,
        "duration": service.duration,
        "image_url": primary_image,
        "images": images,
        "category": service.category,
        "is_active": service.is_active,
        "created_at": _safe_isoformat(service.created_at)
    }
    if include_reviews and service.reviews:
        data["reviews"] = [review_to_dict(r) for r in service.reviews]
        data.update(_calculate_reviews_stats(service.reviews))
    return data

def order_to_dict(order: Order) -> dict:
    return {
        "id": order.id,
        "user_id": order.user_id,
        "status": _safe_enum_value(order.status),
        "subtotal": order.subtotal,
        "tax": order.tax,
        "shipping": order.shipping,
        "total": order.total,
        "shipping_address": order.shipping_address or {},
        "notes": order.notes,
        "tracking_number": order.tracking_number,
        "created_at": _safe_isoformat(order.created_at),
        "updated_at": _safe_isoformat(order.updated_at),
        "items": [order_item_to_dict(item) for item in order.items] if order.items else [],
        "status_history": [status_history_to_dict(h) for h in order.status_history] if order.status_history else []
    }

def order_item_to_dict(item: OrderItem) -> dict:
    return {
        "id": item.id,
        "product_id": item.product_id,
        "product_name": item.product_name,
        "product_image": item.product_image,
        "quantity": item.quantity,
        "price": item.price
    }

def status_history_to_dict(history: OrderStatusHistory) -> dict:
    return {
        "id": history.id,
        "status": _safe_enum_value(history.status, None),
        "notes": history.notes,
        "created_at": _safe_isoformat(history.created_at)
    }

def review_to_dict(review: Review) -> dict:
    return {
        "id": review.id,
        "user_id": review.user_id,
        "user_name": review.user.name if review.user else "Anonymous",
        "product_id": review.product_id,
        "service_id": review.service_id,
        "rating": review.rating,
        "title": review.title,
        "comment": review.comment,
        "is_verified_purchase": review.is_verified_purchase,
        "created_at": _safe_isoformat(review.created_at)
    }

def booking_to_dict(booking: Booking) -> dict:
    return {
        "id": booking.id,
        "service_id": booking.service_id,
        "service_name": booking.service_name,
        "name": booking.name,
        "email": booking.email,
        "phone": booking.phone,
        "preferred_date": booking.preferred_date,
        "notes": booking.notes,
        "status": booking.status,
        "created_at": booking.created_at.isoformat() if booking.created_at else None,
        "completed_at": booking.completed_at.isoformat() if booking.completed_at else None,
        "diagnosis": booking.diagnosis,
        "work_performed": booking.work_performed,
        "technician_notes": booking.technician_notes,
        "service_cost": booking.service_cost,
        "paid": booking.paid,
        "paid_at": booking.paid_at.isoformat() if booking.paid_at else None,
        "device_model": booking.device_model,
        "serial_number": booking.serial_number,
        "product_number": booking.product_number,
        "screen_size": booking.screen_size
    }

# Booking completion model
class BookingComplete(BaseModel):
    diagnosis: Optional[str] = None
    work_performed: Optional[str] = None
    technician_notes: Optional[str] = None
    service_cost: Optional[float] = None
    paid: Optional[bool] = None
    device_model: Optional[str] = None
    serial_number: Optional[str] = None
    product_number: Optional[str] = None
    screen_size: Optional[str] = None

# ================== NOTIFICATION FUNCTIONS ==================

async def send_email_notification(subject: str, body: str, to_email: str = None):
    """Send email notification to admin"""
    if not SMTP_USER or not SMTP_PASSWORD:
        logger.warning("Email notification skipped - SMTP not configured")
        return False
    
    try:
        to_email = to_email or ADMIN_EMAIL
        msg = MIMEMultipart()
        msg['From'] = SMTP_USER
        msg['To'] = to_email
        msg['Subject'] = subject
        msg.attach(MIMEText(body, 'html'))
        
        with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
            server.starttls()
            server.login(SMTP_USER, SMTP_PASSWORD)
            server.send_message(msg)
        
        logger.info(f"Email notification sent to {to_email}")
        return True
    except Exception as e:
        logger.error(f"Failed to send email: {e}")
        return False

async def send_whatsapp_notification(message: str, phone: str = None):
    """Send WhatsApp notification using CallMeBot API or similar service"""
    if not WHATSAPP_API_URL or not WHATSAPP_API_KEY:
        logger.warning("WhatsApp notification skipped - API not configured")
        return False
    
    try:
        phone = phone or ADMIN_PHONE
        # CallMeBot API format: https://api.callmebot.com/whatsapp.php?phone=PHONE&text=MESSAGE&apikey=KEY
        async with httpx.AsyncClient() as client:
            params = {
                'phone': phone.replace('+', ''),
                'text': message,
                'apikey': WHATSAPP_API_KEY
            }
            response = await client.get(WHATSAPP_API_URL, params=params, timeout=10)
            if response.status_code == 200:
                logger.info(f"WhatsApp notification sent to {phone}")
                return True
            else:
                logger.error(f"WhatsApp API error: {response.status_code}")
                return False
    except Exception as e:
        logger.error(f"Failed to send WhatsApp: {e}")
        return False

async def notify_booking(booking_data: dict, service_name: str):
    """Send booking notifications via email and WhatsApp"""
    # Format the booking details
    booking_date = booking_data.get('preferred_date', 'Not specified')
    customer_name = booking_data.get('name', 'Unknown')
    customer_email = booking_data.get('email', 'Not provided')
    customer_phone = booking_data.get('phone', 'Not provided')
    notes = booking_data.get('notes', 'None')
    
    # Email body (HTML)
    email_body = f"""
    <html>
    <body style="font-family: Arial, sans-serif; padding: 20px;">
        <h2 style="color: #2563eb;">New Service Booking!</h2>
        <p>A customer has booked a service on your website.</p>
        <table style="border-collapse: collapse; width: 100%; max-width: 500px;">
            <tr><td style="padding: 8px; font-weight: bold; border-bottom: 1px solid #eee;">Service:</td>
                <td style="padding: 8px; border-bottom: 1px solid #eee;">{service_name}</td></tr>
            <tr><td style="padding: 8px; font-weight: bold; border-bottom: 1px solid #eee;">Customer Name:</td>
                <td style="padding: 8px; border-bottom: 1px solid #eee;">{customer_name}</td></tr>
            <tr><td style="padding: 8px; font-weight: bold; border-bottom: 1px solid #eee;">Email:</td>
                <td style="padding: 8px; border-bottom: 1px solid #eee;">{customer_email}</td></tr>
            <tr><td style="padding: 8px; font-weight: bold; border-bottom: 1px solid #eee;">Phone:</td>
                <td style="padding: 8px; border-bottom: 1px solid #eee;">{customer_phone}</td></tr>
            <tr><td style="padding: 8px; font-weight: bold; border-bottom: 1px solid #eee;">Preferred Date:</td>
                <td style="padding: 8px; border-bottom: 1px solid #eee;">{booking_date}</td></tr>
            <tr><td style="padding: 8px; font-weight: bold; border-bottom: 1px solid #eee;">Notes:</td>
                <td style="padding: 8px; border-bottom: 1px solid #eee;">{notes}</td></tr>
        </table>
        <p style="margin-top: 20px;">Please reach out to the customer as soon as possible.</p>
        <p style="color: #666;">- PromptTech Solutions</p>
    </body>
    </html>
    """
    
    # WhatsApp message (plain text)
    whatsapp_msg = f"""🔔 NEW BOOKING!
    
Service: {service_name}
Customer: {customer_name}
Phone: {customer_phone}
Email: {customer_email}
Date: {booking_date}
Notes: {notes}

Please reach out to the customer."""

    # Send both notifications (don't block on failures)
    await send_email_notification(
        subject=f"New Booking: {service_name} - {customer_name}",
        body=email_body
    )
    await send_whatsapp_notification(whatsapp_msg)

# ================== AUTH ROUTES ==================

@api_router.post("/auth/register", response_model=TokenResponse)
async def register(user_data: UserCreate, db: AsyncSession = Depends(get_db)):
    # Check if email already exists
    result = await db.execute(select(User).where(User.email == user_data.email))
    if result.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Email already registered")
    
    # Generate verification token
    verification_token = serializer.dumps(user_data.email, salt='email-verification')
    
    # Hash password asynchronously (doesn't block event loop)
    hashed_password = await hash_password_async(user_data.password)
    
    # Create user with unverified email
    user = User(
        email=user_data.email,
        name=user_data.name,
        password=hashed_password,
        role=UserRole.USER,
        email_verified=False,
        verification_token=verification_token,
        oauth_provider=None  # Regular email registration
    )
    db.add(user)
    await db.commit()
    await db.refresh(user)
    
    # Send verification email
    try:
        first_name = user_data.name.split()[0] if user_data.name else "User"
        await send_verification_email(user_data.email, first_name, verification_token)
        logger.info(f"Verification email sent to {user_data.email}")
    except Exception as e:
        logger.error(f"Failed to send verification email: {e}")
        # Don't fail registration if email fails
    
    # Return token (user can browse but some features may require verification)
    token = create_access_token({"sub": user.id})
    return TokenResponse(access_token=token, user=user_to_dict(user))

@api_router.get("/auth/verify-email")
async def verify_email(token: str, db: AsyncSession = Depends(get_db)):
    try:
        # Decode token (expires in 24 hours)
        email = serializer.loads(token, salt='email-verification', max_age=86400)
    except Exception as e:
        logger.error(f"Invalid verification token: {e}")
        raise HTTPException(status_code=400, detail="Invalid or expired verification token")
    
    # Find user by email and token
    result = await db.execute(
        select(User).where(
            and_(
                User.email == email,
                User.verification_token == token
            )
        )
    )
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    if user.email_verified:
        return {"message": "Email already verified", "verified": True}
    
    # Mark email as verified
    user.email_verified = True
    user.verification_token = None
    await db.commit()
    
    # Send welcome email
    try:
        first_name = user.name.split()[0] if user.name else "User"
        await send_welcome_email(user.email, first_name)
    except Exception as e:
        logger.error(f"Failed to send welcome email: {e}")
    
    logger.info(f"Email verified for user {user.email}")
    return {"message": "Email verified successfully", "verified": True}

# OAuth Routes
@api_router.get("/auth/google")
async def google_login(request: Request):
    redirect_uri = os.getenv('GOOGLE_REDIRECT_URI', 'http://localhost:8181/api/auth/google/callback')
    return await oauth.google.authorize_redirect(request, redirect_uri)

@api_router.get("/auth/google/callback")
async def google_callback(request: Request, db: AsyncSession = Depends(get_db)):
    try:
        token = await oauth.google.authorize_access_token(request)
        user_info = token.get('userinfo')
        
        if not user_info:
            raise HTTPException(status_code=400, detail="Failed to get user info from Google")
        
        email = user_info.get('email')
        name = user_info.get('name', email.split('@')[0])
        oauth_id = user_info.get('sub')
        
        # Check if user exists
        result = await db.execute(select(User).where(User.email == email))
        user = result.scalar_one_or_none()
        
        if user:
            # Update OAuth info if needed
            if not user.oauth_provider:
                user.oauth_provider = 'google'
                user.oauth_id = oauth_id
                user.email_verified = True  # Google emails are verified
                await db.commit()
        else:
            # Create new user
            user = User(
                email=email,
                name=name,
                password=None,  # No password for OAuth users
                role=UserRole.USER,
                email_verified=True,
                oauth_provider='google',
                oauth_id=oauth_id
            )
            db.add(user)
            await db.commit()
            await db.refresh(user)
            
            # Send welcome email
            try:
                first_name = name.split()[0] if name else "User"
                await send_welcome_email(email, first_name)
            except Exception as e:
                logger.error(f"Failed to send welcome email: {e}")
        
        # Create JWT token
        access_token = create_access_token({"sub": user.id})
        
        # Redirect to frontend with token
        return RedirectResponse(url=f"{FRONTEND_URL}/login?token={access_token}")
        
    except Exception as e:
        logger.error(f"Google OAuth error: {e}")
        return RedirectResponse(url=f"{FRONTEND_URL}/login?error=auth_failed")

@api_router.get("/auth/facebook")
async def facebook_login(request: Request):
    redirect_uri = os.getenv('FACEBOOK_REDIRECT_URI', 'http://localhost:8181/api/auth/facebook/callback')
    return await oauth.facebook.authorize_redirect(request, redirect_uri)

@api_router.get("/auth/facebook/callback")
async def facebook_callback(request: Request, db: AsyncSession = Depends(get_db)):
    try:
        token = await oauth.facebook.authorize_access_token(request)
        
        # Get user info from Facebook
        async with httpx.AsyncClient() as client:
            resp = await client.get(
                'https://graph.facebook.com/me',
                params={'fields': 'id,name,email', 'access_token': token['access_token']}
            )
            user_info = resp.json()
        
        email = user_info.get('email')
        if not email:
            raise HTTPException(status_code=400, detail="Email not provided by Facebook")
        
        name = user_info.get('name', email.split('@')[0])
        oauth_id = user_info.get('id')
        
        # Check if user exists
        result = await db.execute(select(User).where(User.email == email))
        user = result.scalar_one_or_none()
        
        if user:
            if not user.oauth_provider:
                user.oauth_provider = 'facebook'
                user.oauth_id = oauth_id
                user.email_verified = True
                await db.commit()
        else:
            user = User(
                email=email,
                name=name,
                password=None,
                role=UserRole.USER,
                email_verified=True,
                oauth_provider='facebook',
                oauth_id=oauth_id
            )
            db.add(user)
            await db.commit()
            await db.refresh(user)
            
            try:
                first_name = name.split()[0] if name else "User"
                await send_welcome_email(email, first_name)
            except Exception as e:
                logger.error(f"Failed to send welcome email: {e}")
        
        access_token = create_access_token({"sub": user.id})
        return RedirectResponse(url=f"{FRONTEND_URL}/login?token={access_token}")
        
    except Exception as e:
        logger.error(f"Facebook OAuth error: {e}")
        return RedirectResponse(url=f"{FRONTEND_URL}/login?error=auth_failed")

@api_router.get("/auth/yahoo")
async def yahoo_login(request: Request):
    redirect_uri = os.getenv('YAHOO_REDIRECT_URI', 'http://localhost:8181/api/auth/yahoo/callback')
    return await oauth.yahoo.authorize_redirect(request, redirect_uri)

@api_router.get("/auth/yahoo/callback")
async def yahoo_callback(request: Request, db: AsyncSession = Depends(get_db)):
    try:
        token = await oauth.yahoo.authorize_access_token(request)
        
        # Get user info from Yahoo
        async with httpx.AsyncClient() as client:
            resp = await client.get(
                'https://api.login.yahoo.com/openid/v1/userinfo',
                headers={'Authorization': f"Bearer {token['access_token']}"}
            )
            user_info = resp.json()
        
        email = user_info.get('email')
        if not email:
            raise HTTPException(status_code=400, detail="Email not provided by Yahoo")
        
        name = user_info.get('name', email.split('@')[0])
        oauth_id = user_info.get('sub')
        
        # Check if user exists
        result = await db.execute(select(User).where(User.email == email))
        user = result.scalar_one_or_none()
        
        if user:
            if not user.oauth_provider:
                user.oauth_provider = 'yahoo'
                user.oauth_id = oauth_id
                user.email_verified = True
                await db.commit()
        else:
            user = User(
                email=email,
                name=name,
                password=None,
                role=UserRole.USER,
                email_verified=True,
                oauth_provider='yahoo',
                oauth_id=oauth_id
            )
            db.add(user)
            await db.commit()
            await db.refresh(user)
            
            try:
                first_name = name.split()[0] if name else "User"
                await send_welcome_email(email, first_name)
            except Exception as e:
                logger.error(f"Failed to send welcome email: {e}")
        
        access_token = create_access_token({"sub": user.id})
        return RedirectResponse(url=f"{FRONTEND_URL}/login?token={access_token}")
        
    except Exception as e:
        logger.error(f"Yahoo OAuth error: {e}")
        return RedirectResponse(url=f"{FRONTEND_URL}/login?error=auth_failed")

@api_router.post("/auth/login", response_model=TokenResponse)
async def login(credentials: UserLogin, db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User).where(User.email == credentials.email))
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    # Check if user registered with OAuth
    if user.oauth_provider and not user.password:
        raise HTTPException(
            status_code=400, 
            detail=f"This account uses {user.oauth_provider} login. Please sign in with {user.oauth_provider}."
        )
    
    # Verify password (use async to prevent blocking)
    if not user.password or not await verify_password_async(credentials.password, user.password):
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    token = create_access_token({"sub": user.id})
    return TokenResponse(access_token=token, user=user_to_dict(user))

@api_router.get("/auth/me")
async def get_me(user: User = Depends(get_current_user)):
    return user_to_dict(user)

# ================== PRODUCTS ROUTES ==================

@api_router.get("/products")
async def get_products(
    response: Response,
    category: Optional[str] = None,
    search: Optional[str] = None,
    min_price: Optional[float] = None,
    max_price: Optional[float] = None,
    in_stock: Optional[bool] = None,
    db: AsyncSession = Depends(get_db)
):
    # Add cache headers for better performance
    response.headers["Cache-Control"] = "public, max-age=60"  # Cache for 60 seconds
    
    query = select(Product).where(Product.is_active == True).options(selectinload(Product.images))
    
    if category and category != "all":
        query = query.where(Product.category == category)
    if search:
        query = query.where(
            or_(
                Product.name.ilike(f"%{search}%"),
                Product.description.ilike(f"%{search}%"),
                Product.brand.ilike(f"%{search}%")
            )
        )
    if min_price is not None:
        query = query.where(Product.price >= min_price)
    if max_price is not None:
        query = query.where(Product.price <= max_price)
    if in_stock:
        query = query.where(Product.stock > 0)
    
    query = query.options(selectinload(Product.reviews).selectinload(Review.user))
    result = await db.execute(query)
    products = result.scalars().all()
    return [product_to_dict(p, include_reviews=True) for p in products]

@api_router.get("/products/{product_id}")
async def get_product(product_id: str, db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Product)
        .where(Product.id == product_id)
        .options(
            selectinload(Product.images),
            selectinload(Product.reviews).selectinload(Review.user)
        )
    )
    product = result.scalar_one_or_none()
    if not product:
        raise HTTPException(status_code=404, detail="Product not found")
    return product_to_dict(product, include_reviews=True)

@api_router.get("/products/categories/list")
async def get_product_categories(db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(Product.category).distinct())
    categories = [row[0] for row in result.fetchall()]
    return categories

# ================== SERVICES ROUTES ==================

@api_router.get("/services")
async def get_services(
    response: Response,
    category: Optional[str] = None,
    db: AsyncSession = Depends(get_db)
):
    # Add cache headers for better performance
    response.headers["Cache-Control"] = "public, max-age=60"  # Cache for 60 seconds
    
    query = select(Service).where(Service.is_active == True).options(selectinload(Service.images))
    if category and category != "all":
        query = query.where(Service.category == category)
    query = query.options(selectinload(Service.reviews).selectinload(Review.user))
    result = await db.execute(query)
    services = result.scalars().all()
    return [service_to_dict(s, include_reviews=True) for s in services]

@api_router.get("/services/{service_id}")
async def get_service(service_id: str, db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Service)
        .where(Service.id == service_id)
        .options(
            selectinload(Service.images),
            selectinload(Service.reviews).selectinload(Review.user)
        )
    )
    service = result.scalar_one_or_none()
    if not service:
        raise HTTPException(status_code=404, detail="Service not found")
    return service_to_dict(service, include_reviews=True)

@api_router.post("/services/book")
async def book_service(
    booking_data: BookingCreate,
    user: Optional[User] = Depends(get_optional_user),
    db: AsyncSession = Depends(get_db)
):
    result = await db.execute(select(Service).where(Service.id == booking_data.service_id))
    service = result.scalar_one_or_none()
    if not service:
        raise HTTPException(status_code=404, detail="Service not found")
    
    booking = Booking(
        service_id=booking_data.service_id,
        user_id=user.id if user else None,
        name=booking_data.name,
        email=booking_data.email,
        phone=booking_data.phone,
        preferred_date=booking_data.preferred_date,
        notes=booking_data.notes,
        service_name=service.name
    )
    db.add(booking)
    await db.commit()
    
    # Send notifications to admin (email + WhatsApp)
    try:
        await notify_booking({
            'name': booking_data.name,
            'email': booking_data.email,
            'phone': booking_data.phone,
            'preferred_date': booking_data.preferred_date,
            'notes': booking_data.notes
        }, service.name)
    except Exception as e:
        logger.error(f"Failed to send booking notifications: {e}")
        # Don't fail the booking if notifications fail
    
    return {"message": "Booking created successfully", "booking_id": booking.id}

# ================== CART ROUTES ==================

@api_router.get("/cart")
async def get_cart(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(CartItem)
        .where(CartItem.user_id == user.id)
        .options(
            selectinload(CartItem.product).selectinload(Product.images)
        )
    )
    cart_items = result.scalars().all()
    return [{
        "id": item.id,
        "product_id": item.product_id,
        "quantity": item.quantity,
        "product": product_to_dict(item.product) if item.product else None
    } for item in cart_items]

@api_router.post("/cart/add")
async def add_to_cart(item: CartItemCreate, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(Product).where(Product.id == item.product_id))
    product = result.scalar_one_or_none()
    if not product:
        raise HTTPException(status_code=404, detail="Product not found")
    
    result = await db.execute(
        select(CartItem).where(
            and_(CartItem.user_id == user.id, CartItem.product_id == item.product_id)
        )
    )
    existing = result.scalar_one_or_none()
    
    if existing:
        existing.quantity += item.quantity
    else:
        cart_item = CartItem(user_id=user.id, product_id=item.product_id, quantity=item.quantity)
        db.add(cart_item)
    
    await db.commit()
    return {"message": "Item added to cart"}

@api_router.put("/cart/{item_id}")
async def update_cart_item(item_id: str, quantity: int = Query(...), user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(CartItem).where(and_(CartItem.id == item_id, CartItem.user_id == user.id))
    )
    item = result.scalar_one_or_none()
    if not item:
        raise HTTPException(status_code=404, detail="Cart item not found")
    
    if quantity <= 0:
        await db.delete(item)
    else:
        item.quantity = quantity
    
    await db.commit()
    return {"message": "Cart updated"}

@api_router.delete("/cart/{item_id}")
async def remove_from_cart(item_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(CartItem).where(and_(CartItem.id == item_id, CartItem.user_id == user.id))
    )
    item = result.scalar_one_or_none()
    if item:
        await db.delete(item)
        await db.commit()
    return {"message": "Item removed from cart"}

@api_router.delete("/cart")
async def clear_cart(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    await db.execute(
        CartItem.__table__.delete().where(CartItem.user_id == user.id)
    )
    await db.commit()
    return {"message": "Cart cleared"}

# ================== ORDERS ROUTES ==================

@api_router.post("/orders")
async def create_order(order_data: OrderCreate, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    # Get cart items
    result = await db.execute(
        select(CartItem)
        .where(CartItem.user_id == user.id)
        .options(selectinload(CartItem.product))
    )
    cart_items = result.scalars().all()
    
    if not cart_items:
        raise HTTPException(status_code=400, detail="Cart is empty")
    
    # Calculate totals
    subtotal = sum(item.product.price * item.quantity for item in cart_items)
    tax = subtotal * 0.08
    shipping = 0 if subtotal > 100 else 9.99
    total = subtotal + tax + shipping
    
    # Create order
    order = Order(
        user_id=user.id,
        status=OrderStatus.PENDING,
        subtotal=subtotal,
        tax=tax,
        shipping=shipping,
        total=total,
        shipping_address=order_data.shipping_address,
        notes=order_data.notes
    )
    db.add(order)
    await db.flush()
    
    # Create order items and update inventory
    for cart_item in cart_items:
        product = cart_item.product
        order_item = OrderItem(
            order_id=order.id,
            product_id=product.id,
            quantity=cart_item.quantity,
            price=product.price,
            product_name=product.name,
            product_image=product.image_url
        )
        db.add(order_item)
        
        # Update stock
        previous_stock = product.stock
        product.stock = max(0, product.stock - cart_item.quantity)
        
        # Log inventory change
        inv_log = InventoryLog(
            product_id=product.id,
            action="sale",
            quantity_change=-cart_item.quantity,
            previous_stock=previous_stock,
            new_stock=product.stock,
            notes=f"Order {order.id}",
            created_by=user.id
        )
        db.add(inv_log)
    
    # Add status history
    status_history = OrderStatusHistory(
        order_id=order.id,
        status=OrderStatus.PENDING,
        notes="Order placed",
        created_by=user.id
    )
    db.add(status_history)
    
    # Clear cart
    await db.execute(CartItem.__table__.delete().where(CartItem.user_id == user.id))
    
    await db.commit()
    await db.refresh(order)
    
    return {"message": "Order created successfully", "order_id": order.id}

@api_router.get("/orders")
async def get_orders(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Order)
        .where(Order.user_id == user.id)
        .options(selectinload(Order.items), selectinload(Order.status_history))
        .order_by(desc(Order.created_at))
    )
    orders = result.scalars().all()
    return [order_to_dict(o) for o in orders]

@api_router.get("/orders/{order_id}")
async def get_order(order_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Order)
        .where(and_(Order.id == order_id, Order.user_id == user.id))
        .options(selectinload(Order.items), selectinload(Order.status_history))
    )
    order = result.scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="Order not found")
    return order_to_dict(order)

# ================== REVIEWS ROUTES ==================

@api_router.post("/reviews")
async def create_review(review_data: ReviewCreate, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    if not review_data.product_id and not review_data.service_id:
        raise HTTPException(status_code=400, detail="Product or service ID required")
    
    if review_data.rating < 1 or review_data.rating > 5:
        raise HTTPException(status_code=400, detail="Rating must be between 1 and 5")
    
    # Check for verified purchase
    is_verified = False
    if review_data.product_id:
        result = await db.execute(
            select(OrderItem)
            .join(Order)
            .where(
                and_(
                    Order.user_id == user.id,
                    OrderItem.product_id == review_data.product_id,
                    Order.status.in_([OrderStatus.DELIVERED, OrderStatus.SHIPPED])
                )
            )
        )
        if result.scalar_one_or_none():
            is_verified = True
    
    review = Review(
        user_id=user.id,
        product_id=review_data.product_id,
        service_id=review_data.service_id,
        rating=review_data.rating,
        title=review_data.title,
        comment=review_data.comment,
        is_verified_purchase=is_verified
    )
    db.add(review)
    await db.commit()
    await db.refresh(review)
    
    return {"message": "Review submitted successfully", "review_id": review.id}

@api_router.get("/reviews/product/{product_id}")
async def get_product_reviews(product_id: str, db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Review)
        .where(and_(Review.product_id == product_id, Review.is_approved == True))
        .options(selectinload(Review.user))
        .order_by(desc(Review.created_at))
    )
    reviews = result.scalars().all()
    return [review_to_dict(r) for r in reviews]

@api_router.get("/reviews/service/{service_id}")
async def get_service_reviews(service_id: str, db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Review)
        .where(and_(Review.service_id == service_id, Review.is_approved == True))
        .options(selectinload(Review.user))
        .order_by(desc(Review.created_at))
    )
    reviews = result.scalars().all()
    return [review_to_dict(r) for r in reviews]

# ================== CONTACT ROUTES ==================

@api_router.post("/contact")
async def submit_contact(contact_data: ContactCreate, db: AsyncSession = Depends(get_db)):
    contact = Contact(
        name=contact_data.name,
        email=contact_data.email,
        subject=contact_data.subject,
        message=contact_data.message
    )
    db.add(contact)
    await db.commit()
    return {"message": "Message sent successfully", "id": contact.id}

# ================== ADMIN ROUTES ==================

# Admin - Dashboard Stats
@api_router.get("/admin/dashboard")
async def get_admin_dashboard(user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    """Admin dashboard with comprehensive stats and error handling"""
    
    async def safe_scalar(query, default=0, error_msg=""):
        """Execute query and return scalar with error handling"""
        try:
            result = await db.execute(query)
            value = result.scalar()
            return float(value) if value is not None and isinstance(value, (int, float)) else default
        except Exception as e:
            if error_msg:
                logger.error(f"{error_msg}: {e}")
            return default
    
    try:
        today = datetime.now(timezone.utc).date()
        month_ago = today - timedelta(days=30)
        month_start = datetime.combine(month_ago, datetime.min.time())
        
        # Batch count queries for better performance
        counts_queries = {
            "products": select(func.count(Product.id)),
            "services": select(func.count(Service.id)),
            "users": select(func.count(User.id)),
            "orders": select(func.count(Order.id))
        }
        
        counts = {}
        for key, query in counts_queries.items():
            counts[key] = await safe_scalar(query, 0, f"Error fetching {key} count")
        
        # Revenue queries
        total_revenue = await safe_scalar(
            select(func.sum(Order.total)),
            0.0, "Error fetching total revenue"
        )
        monthly_revenue = await safe_scalar(
            select(func.sum(Order.total)).where(Order.created_at >= month_start),
            0.0, "Error fetching monthly revenue"
        )
    
        # Today's stats - batch queries
        today_orders = await safe_scalar(
            select(func.count(Order.id)).where(func.date(Order.created_at) == today),
            0, "Error fetching today's orders"
        )
        today_revenue = await safe_scalar(
            select(func.sum(Order.total)).where(func.date(Order.created_at) == today),
            0.0, "Error fetching today's revenue"
        )
        pending_bookings = await safe_scalar(
            select(func.count(Booking.id)).where(Booking.status == "pending"),
            0, "Error fetching pending bookings"
        )
        
# Low stock products
        low_stock_products = []
        try:
            low_stock_result = await db.execute(
                select(Product)
                .where(Product.stock <= Product.low_stock_threshold, Product.is_active == True)
            )
            low_stock_products = [{
                "id": p.id, "name": p.name, "stock": p.stock,
                "low_stock_threshold": p.low_stock_threshold, "category": p.category
            } for p in low_stock_result.scalars().all()]
        except Exception as e:
            logger.error(f"Error fetching low stock products: {e}")
        
        # Recent orders
        recent_orders_data = []
        try:
            recent_orders_result = await db.execute(
                select(Order)
                .options(selectinload(Order.items))
                .order_by(desc(Order.created_at))
                .limit(10)
            )
            
            for order in recent_orders_result.scalars().all():
                try:
                    recent_orders_data.append({
                        "id": order.id,
                        "status": _safe_enum_value(order.status),
                        "total": float(order.total) if order.total is not None else 0.0,
                        "created_at": _safe_isoformat(order.created_at),
                        "items": [{"id": i.id, "product_name": i.product_name, "quantity": i.quantity} for i in order.items] if order.items else []
                    })
                except Exception as e:
                    logger.warning(f"Error processing order {order.id}: {e}")
        except Exception as e:
            logger.error(f"Error fetching recent orders: {e}")
        
        # Build response
        response = {
            "stats": {
                "total_products": int(counts["products"]),
                "total_services": int(counts["services"]),
                "total_users": int(counts["users"]),
                "total_orders": int(counts["orders"]),
                "total_revenue": total_revenue,
                "monthly_revenue": monthly_revenue,
                "today_orders": int(today_orders),
                "today_revenue": today_revenue,
                "pending_bookings": int(pending_bookings)
            },
            "low_stock_products": low_stock_products,
            "recent_orders": recent_orders_data
        }
        
        logger.info(f"Dashboard data fetched successfully for user {user.id}")
        return response
        
    except Exception as e:
        logger.error(f"Critical error in get_admin_dashboard: {e}", exc_info=True)
        # Return safe defaults instead of crashing
        return {
            "stats": {
                "total_products": 0,
                "total_services": 0,
                "total_users": 0,
                "total_orders": 0,
                "total_revenue": 0.0,
                "monthly_revenue": 0.0,
                "today_orders": 0,
                "today_revenue": 0.0,
                "pending_bookings": 0
            },
            "low_stock_products": [],
            "recent_orders": [],
            "error": "Failed to load some dashboard data"
        }

# ================== IMAGE UPLOAD ROUTES ==================

@api_router.post("/upload/image")
async def upload_image(
    file: UploadFile = File(...),
    user: User = Depends(get_admin_user)
):
    """Upload a product image and return the URL"""
    try:
        logger.info(f"=== Image Upload Request ===")
        logger.info(f"Filename: '{file.filename}'")
        logger.info(f"Content-Type: {file.content_type}")
        logger.info(f"File size: {file.size if hasattr(file, 'size') else 'unknown'}")
        
        # Handle cases where filename might be None or empty
        if not file.filename:
            logger.error("No filename provided")
            raise HTTPException(status_code=400, detail="No filename provided")
        
        # Validate file extension (more reliable than content_type)
        file_ext = Path(file.filename).suffix.lower()
        logger.info(f"Extracted extension: '{file_ext}'")
        
        # Handle cases where file has no extension - try to infer from content_type
        if not file_ext and file.content_type:
            content_type_map = {
                'image/jpeg': '.jpg',
                'image/jpg': '.jpg',
                'image/png': '.png',
                'image/gif': '.gif',
                'image/webp': '.webp',
                'image/bmp': '.bmp',
                'image/svg+xml': '.svg',
                'image/heic': '.heic',
                'image/heif': '.heif'
            }
            file_ext = content_type_map.get(file.content_type, '')
            logger.info(f"Inferred extension from content-type: '{file_ext}'")
        
        # Support common image formats including iPhone formats
        allowed_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg', '.heic', '.heif'}
        
        # Special handling for HEIC/HEIF - convert to JPG for better compatibility
        convert_to_jpg = file_ext in {'.heic', '.heif'}
        if convert_to_jpg:
            logger.info(f"HEIC/HEIF file detected, will convert to JPG for compatibility")
        
        if not file_ext or file_ext not in allowed_extensions:
            logger.warning(f"Invalid or missing file extension: '{file_ext}'")
            logger.warning(f"Full filename: '{file.filename}'")
            raise HTTPException(
                status_code=400, 
                detail=f"File must be an image with a valid extension. Allowed: {', '.join(sorted(allowed_extensions))}"
            )
        
        # Generate unique filename - convert HEIC to JPG extension
        output_ext = '.jpg' if convert_to_jpg else file_ext
        unique_filename = f"{uuid.uuid4()}{output_ext}"
        file_path = UPLOAD_DIR / unique_filename
        
        logger.info(f"Saving file to: {file_path}")
        
        # Save file asynchronously
        content = await file.read()
        if len(content) == 0:
            raise HTTPException(status_code=400, detail="File is empty")
        
        with open(file_path, "wb") as buffer:
            buffer.write(content)
        
        # Return relative URL
        # Convert HEIC/HEIF to JPG for better browser compatibility
        if convert_to_jpg:
            try:
                from PIL import Image
                from io import BytesIO
                
                # Try to use pillow_heif if available
                try:
                    import pillow_heif
                    pillow_heif.register_heif_opener()
                except ImportError:
                    logger.warning("pillow_heif not installed, HEIC conversion may not work")
                
                # Open and convert image
                img = Image.open(BytesIO(content))
                img = img.convert('RGB')  # Ensure RGB mode for JPEG
                img.save(file_path, 'JPEG', quality=90)
                logger.info(f"Converted HEIC/HEIF to JPG successfully")
            except Exception as e:
                logger.error(f"Failed to convert HEIC/HEIF: {e}")
                # Fallback: save as-is and let browser handle it
                with open(file_path, "wb") as buffer:
                    buffer.write(content)
                logger.info(f"Saved HEIC file as-is without conversion")
        else:
            with open(file_path, "wb") as buffer:
                buffer.write(content)
        
        # Return relative URL
        image_url = f"/uploads/products/{unique_filename}"
        logger.info(f"Image uploaded successfully: {image_url}, size: {len(content)} bytes")
        return {"url": image_url, "filename": unique_filename}
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to upload image: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"Failed to upload image: {str(e)}")

@api_router.post("/admin/products/{product_id}/images")
async def add_product_images(
    product_id: str,
    image_urls: List[str],
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Add multiple images to a product"""
    product = await _get_or_404(db, Product, product_id, "Product not found")
    
    # Get current max display order
    result = await db.execute(
        select(func.max(ProductImage.display_order))
        .where(ProductImage.product_id == product_id)
    )
    max_order = result.scalar() or -1
    
    # Add new images
    for idx, url in enumerate(image_urls):
        product_image = ProductImage(
            product_id=product_id,
            image_url=url,
            display_order=max_order + idx + 1,
            is_primary=(max_order == -1 and idx == 0)  # First image is primary if no images exist
        )
        db.add(product_image)
    
    await db.commit()
    
    return {"message": f"Added {len(image_urls)} images", "product_id": product_id}

@api_router.delete("/admin/products/{product_id}/images/{image_id}")
async def delete_product_image(
    product_id: str,
    image_id: str,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Delete a product image"""
    result = await db.execute(
        select(ProductImage)
        .where(and_(ProductImage.id == image_id, ProductImage.product_id == product_id))
    )
    image = result.scalar_one_or_none()
    
    if not image:
        raise HTTPException(status_code=404, detail="Image not found")
    
    # Delete file from filesystem
    try:
        file_path = UPLOAD_DIR / Path(image.image_url).name
        if file_path.exists():
            file_path.unlink()
    except Exception as e:
        logger.warning(f"Failed to delete image file: {e}")
    
    await db.delete(image)
    await db.commit()
    
    return {"message": "Image deleted"}

@api_router.put("/admin/products/{product_id}/images/reorder")
async def reorder_product_images(
    product_id: str,
    image_orders: Dict[str, int],  # {image_id: display_order}
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Reorder product images"""
    for image_id, order in image_orders.items():
        result = await db.execute(
            select(ProductImage)
            .where(and_(ProductImage.id == image_id, ProductImage.product_id == product_id))
        )
        image = result.scalar_one_or_none()
        if image:
            image.display_order = order
    
    await db.commit()
    return {"message": "Images reordered"}

# Admin - Products CRUD
@api_router.get("/admin/products")
async def admin_get_products(
    include_inactive: bool = False,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    query = select(Product).options(selectinload(Product.images))
    if not include_inactive:
        query = query.where(Product.is_active == True)
    query = query.order_by(desc(Product.created_at))
    result = await db.execute(query)
    products = result.scalars().all()
    return [product_to_dict(p) for p in products]

@api_router.post("/admin/products")
async def admin_create_product(product_data: ProductCreate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    data_dict = product_data.model_dump()
    image_urls = data_dict.pop('images', [])
    
    product = Product(**data_dict)
    db.add(product)
    await db.commit()
    await db.refresh(product)
    
    # Add images if provided
    if image_urls:
        for idx, url in enumerate(image_urls):
            product_image = ProductImage(
                product_id=product.id,
                image_url=url,
                display_order=idx,
                is_primary=(idx == 0)
            )
            db.add(product_image)
        await db.commit()
    
    # Log inventory
    inv_log = InventoryLog(
        product_id=product.id,
        action="add",
        quantity_change=product.stock,
        previous_stock=0,
        new_stock=product.stock,
        notes="Initial stock",
        created_by=user.id
    )
    db.add(inv_log)
    await db.commit()
    
    # Reload product with images relationship
    result = await db.execute(
        select(Product)
        .where(Product.id == product.id)
        .options(selectinload(Product.images))
    )
    product = result.scalar_one()
    
    return product_to_dict(product)

@api_router.put("/admin/products/{product_id}")
async def admin_update_product(product_id: str, product_data: ProductUpdate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    product = await _get_or_404(db, Product, product_id, "Product not found")
    update_data = product_data.model_dump(exclude_unset=True)
    image_urls = update_data.pop('images', None)
    
    # Track stock changes
    if "stock" in update_data and update_data["stock"] != product.stock:
        inv_log = InventoryLog(
            product_id=product.id,
            action="adjust",
            quantity_change=update_data["stock"] - product.stock,
            previous_stock=product.stock,
            new_stock=update_data["stock"],
            notes="Manual adjustment",
            created_by=user.id
        )
        db.add(inv_log)
    
    for key, value in update_data.items():
        setattr(product, key, value)
    
    # Update images if provided
    if image_urls is not None:
        # Delete existing images
        await db.execute(
            delete(ProductImage).where(ProductImage.product_id == product_id)
        )
        
        # Add new images
        for idx, url in enumerate(image_urls):
            product_image = ProductImage(
                product_id=product_id,
                image_url=url,
                display_order=idx,
                is_primary=(idx == 0)
            )
            db.add(product_image)
    
    await db.commit()
    
    # Reload product with images relationship
    result = await db.execute(
        select(Product)
        .where(Product.id == product_id)
        .options(selectinload(Product.images))
    )
    product = result.scalar_one()
    
    return product_to_dict(product)

@api_router.delete("/admin/products/{product_id}")
async def admin_delete_product(product_id: str, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    product = await _get_or_404(db, Product, product_id, "Product not found")
    
    # Hard delete - remove from database
    await db.delete(product)
    await db.commit()
    
    return {"message": "Product deleted"}

# Admin - Categories CRUD
@api_router.get("/admin/categories")
async def admin_get_categories(user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(Category).order_by(Category.name))
    categories = result.scalars().all()
    return [{
        "id": str(c.id),
        "name": c.name,
        "description": c.description,
        "created_at": c.created_at.isoformat() if c.created_at else None
    } for c in categories]

@api_router.post("/admin/categories")
async def admin_create_category(category_data: CategoryCreate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    data = category_data.model_dump()
    # Auto-generate slug if not provided
    if not data.get('slug'):
        data['slug'] = data['name'].lower().replace(' ', '-').replace('&', 'and')
    category = Category(**data)
    db.add(category)
    await db.commit()
    await db.refresh(category)
    return {
        "id": str(category.id),
        "name": category.name,
        "slug": category.slug,
        "description": category.description,
        "created_at": category.created_at.isoformat() if category.created_at else None
    }

@api_router.put("/admin/categories/{category_id}")
async def admin_update_category(category_id: str, category_data: CategoryUpdate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    category = await _get_or_404(db, Category, category_id, "Category not found")
    update_data = category_data.model_dump(exclude_unset=True)
    for key, value in update_data.items():
        setattr(category, key, value)
    await db.commit()
    await db.refresh(category)
    return {
        "id": str(category.id),
        "name": category.name,
        "description": category.description,
        "created_at": category.created_at.isoformat() if category.created_at else None
    }

@api_router.delete("/admin/categories/{category_id}")
async def admin_delete_category(category_id: str, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    category = await _get_or_404(db, Category, category_id, "Category not found")
    await db.delete(category)
    await db.commit()
    return {"message": "Category deleted successfully"}

@api_router.get("/categories")
async def get_categories(db: AsyncSession = Depends(get_db)):
    """Public endpoint to get all categories"""
    result = await db.execute(select(Category).order_by(Category.name))
    categories = result.scalars().all()
    return [{
        "id": str(c.id),
        "name": c.name,
        "description": c.description
    } for c in categories]

# Admin - Services CRUD
@api_router.get("/admin/services")
async def admin_get_services(include_inactive: bool = False, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    query = select(Service).options(selectinload(Service.images))
    if not include_inactive:
        query = query.where(Service.is_active == True)
    query = query.order_by(desc(Service.created_at))
    result = await db.execute(query)
    services = result.scalars().all()
    return [service_to_dict(s) for s in services]

@api_router.post("/admin/services")
async def admin_create_service(service_data: ServiceCreate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    data_dict = service_data.model_dump()
    image_urls = data_dict.pop('images', [])
    
    service = Service(**data_dict)
    db.add(service)
    await db.commit()
    await db.refresh(service)
    
    # Add images if provided
    if image_urls:
        for idx, url in enumerate(image_urls):
            service_image = ServiceImage(
                service_id=service.id,
                image_url=url,
                display_order=idx,
                is_primary=(idx == 0)
            )
            db.add(service_image)
        await db.commit()
    
    # Reload service with images relationship
    result = await db.execute(
        select(Service)
        .where(Service.id == service.id)
        .options(selectinload(Service.images))
    )
    service = result.scalar_one()
    
    return service_to_dict(service)

@api_router.put("/admin/services/{service_id}")
async def admin_update_service(service_id: str, service_data: ServiceUpdate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    service = await _get_or_404(db, Service, service_id, "Service not found")
    update_data = service_data.model_dump(exclude_unset=True)
    image_urls = update_data.pop('images', None)
    
    for key, value in update_data.items():
        setattr(service, key, value)
    
    # Update images if provided
    if image_urls is not None:
        # Delete existing images
        await db.execute(
            delete(ServiceImage).where(ServiceImage.service_id == service_id)
        )
        
        # Add new images
        for idx, url in enumerate(image_urls):
            service_image = ServiceImage(
                service_id=service_id,
                image_url=url,
                display_order=idx,
                is_primary=(idx == 0)
            )
            db.add(service_image)
    
    await db.commit()
    
    # Reload service with images relationship
    result = await db.execute(
        select(Service)
        .where(Service.id == service_id)
        .options(selectinload(Service.images))
    )
    service = result.scalar_one()
    
    return service_to_dict(service)

@api_router.delete("/admin/services/{service_id}")
async def admin_delete_service(service_id: str, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    service = await _get_or_404(db, Service, service_id, "Service not found")
    
    # Hard delete - remove from database
    await db.delete(service)
    await db.commit()
    
    return {"message": "Service deleted"}

# Admin - Orders Management
@api_router.get("/admin/orders")
async def admin_get_orders(
    status: Optional[str] = None,
    limit: int = 50,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    query = select(Order).options(selectinload(Order.items), selectinload(Order.status_history), selectinload(Order.user))
    if status:
        query = query.where(Order.status == OrderStatus(status))
    query = query.order_by(desc(Order.created_at)).limit(limit)
    result = await db.execute(query)
    orders = result.scalars().all()
    return [{
        **order_to_dict(o),
        "user_name": o.user.name if o.user else "Unknown",
        "user_email": o.user.email if o.user else "Unknown"
    } for o in orders]

@api_router.put("/admin/orders/{order_id}/status")
async def admin_update_order_status(order_id: str, status_data: OrderStatusUpdate, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(Order).where(Order.id == order_id).options(selectinload(Order.items))
    )
    order = result.scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="Order not found")
    
    new_status = OrderStatus(status_data.status)
    order.status = new_status
    if status_data.tracking_number:
        order.tracking_number = status_data.tracking_number
    
    # Handle refunds - restore stock
    if new_status == OrderStatus.REFUNDED:
        for item in order.items:
            result = await db.execute(select(Product).where(Product.id == item.product_id))
            product = result.scalar_one_or_none()
            if product:
                previous_stock = product.stock
                product.stock += item.quantity
                inv_log = InventoryLog(
                    product_id=product.id,
                    action="refund",
                    quantity_change=item.quantity,
                    previous_stock=previous_stock,
                    new_stock=product.stock,
                    notes=f"Refund for order {order_id}",
                    created_by=user.id
                )
                db.add(inv_log)
    
    # Add status history
    status_history = OrderStatusHistory(
        order_id=order.id,
        status=new_status,
        notes=status_data.notes,
        created_by=user.id
    )
    db.add(status_history)
    
    await db.commit()
    return {"message": "Order status updated"}

# Admin - Inventory Management
@api_router.get("/admin/inventory")
async def admin_get_inventory(user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    try:
        result = await db.execute(
            select(Product)
            .options(selectinload(Product.images))
            .where(Product.is_active == True)
            .order_by(Product.stock)
        )
        products = result.scalars().all()
        
        inventory_data = []
        for p in products:
            product_dict = product_to_dict(p)
            product_dict["is_low_stock"] = p.stock <= p.low_stock_threshold
            inventory_data.append(product_dict)
        
        return inventory_data
    except Exception as e:
        logger.error(f"Error fetching inventory: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to fetch inventory: {str(e)}")

@api_router.post("/admin/inventory/{product_id}/adjust")
async def admin_adjust_inventory(product_id: str, adjustment: InventoryAdjust, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    product = await _get_or_404(db, Product, product_id, "Product not found")
    
    previous_stock = product.stock
    product.stock = max(0, product.stock + adjustment.quantity_change)
    
    inv_log = InventoryLog(
        product_id=product.id,
        action="adjust" if adjustment.quantity_change >= 0 else "remove",
        quantity_change=adjustment.quantity_change,
        previous_stock=previous_stock,
        new_stock=product.stock,
        notes=adjustment.notes,
        created_by=user.id
    )
    db.add(inv_log)
    await db.commit()
    
    return _build_response("Inventory adjusted", new_stock=product.stock)

@api_router.get("/admin/inventory/{product_id}/logs")
async def admin_get_inventory_logs(product_id: str, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(
        select(InventoryLog)
        .where(InventoryLog.product_id == product_id)
        .order_by(desc(InventoryLog.created_at))
        .limit(50)
    )
    logs = result.scalars().all()
    return [{
        "id": log.id,
        "action": log.action,
        "quantity_change": log.quantity_change,
        "previous_stock": log.previous_stock,
        "new_stock": log.new_stock,
        "notes": log.notes,
        "created_at": log.created_at.isoformat() if log.created_at else None
    } for log in logs]

# Admin - Bookings Management
@api_router.get("/admin/bookings")
async def admin_get_bookings(status: Optional[str] = None, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    query = select(Booking).options(selectinload(Booking.service))
    if status:
        query = query.where(Booking.status == status)
    query = query.order_by(desc(Booking.created_at))
    result = await db.execute(query)
    bookings = result.scalars().all()
    return [booking_to_dict(b) for b in bookings]

@api_router.put("/admin/bookings/{booking_id}/status")
async def admin_update_booking_status(booking_id: str, status: str, user: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(Booking).where(Booking.id == booking_id))
    booking = result.scalar_one_or_none()
    if not booking:
        raise HTTPException(status_code=404, detail="Booking not found")
    
    booking.status = status
    await db.commit()
    return {"message": "Booking status updated"}

@api_router.put("/admin/bookings/{booking_id}/complete")
async def admin_complete_booking(
    booking_id: str, 
    completion_data: BookingComplete,
    user: User = Depends(get_admin_user), 
    db: AsyncSession = Depends(get_db)
):
    """Mark a booking as completed with diagnosis and work performed details"""
    result = await db.execute(select(Booking).where(Booking.id == booking_id))
    booking = result.scalar_one_or_none()
    if not booking:
        raise HTTPException(status_code=404, detail="Booking not found")
    
    booking.status = "completed"
    booking.completed_at = datetime.now(timezone.utc)
    if completion_data.diagnosis:
        booking.diagnosis = completion_data.diagnosis
    if completion_data.work_performed:
        booking.work_performed = completion_data.work_performed
    if completion_data.technician_notes:
        booking.technician_notes = completion_data.technician_notes
    if completion_data.service_cost is not None:
        booking.service_cost = completion_data.service_cost
    if completion_data.paid is not None:
        booking.paid = completion_data.paid
        if completion_data.paid:
            booking.paid_at = datetime.now(timezone.utc)
    if completion_data.device_model:
        booking.device_model = completion_data.device_model
    if completion_data.serial_number:
        booking.serial_number = completion_data.serial_number
    if completion_data.product_number:
        booking.product_number = completion_data.product_number
    if completion_data.screen_size:
        booking.screen_size = completion_data.screen_size
    
    await db.commit()
    await db.refresh(booking)
    
    logger.info(f"Booking {booking_id} marked as completed by {user.email}")
    return booking_to_dict(booking)

@api_router.get("/admin/bookings/{booking_id}/receipt")
async def admin_get_booking_receipt(
    booking_id: str,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Get booking receipt data for printing"""
    result = await db.execute(
        select(Booking)
        .where(Booking.id == booking_id)
        .options(selectinload(Booking.service))
    )
    booking = result.scalar_one_or_none()
    if not booking:
        raise HTTPException(status_code=404, detail="Booking not found")
    
    # Get service details
    service_price = booking.service.price if booking.service else 0
    
    return {
        **booking_to_dict(booking),
        "service_base_price": service_price,
        "final_cost": booking.service_cost if booking.service_cost else service_price,
        "company": {
            "name": "PromptTech Solutions",
            "address": "Belmopan City, Cayo District, Belize",
            "phone": "+501 638-6318",
            "email": "prompttechbz@gmail.com"
        }
    }

@api_router.put("/admin/bookings/{booking_id}/update")
async def admin_update_booking(
    booking_id: str, 
    update_data: BookingComplete,
    user: User = Depends(get_admin_user), 
    db: AsyncSession = Depends(get_db)
):
    """Update booking details without marking as complete"""
    result = await db.execute(select(Booking).where(Booking.id == booking_id))
    booking = result.scalar_one_or_none()
    if not booking:
        raise HTTPException(status_code=404, detail="Booking not found")
    
    if update_data.diagnosis is not None:
        booking.diagnosis = update_data.diagnosis
    if update_data.work_performed is not None:
        booking.work_performed = update_data.work_performed
    if update_data.technician_notes is not None:
        booking.technician_notes = update_data.technician_notes
    if update_data.service_cost is not None:
        booking.service_cost = update_data.service_cost
    
    await db.commit()
    await db.refresh(booking)
    
    logger.info(f"Booking {booking_id} updated by {user.email}")
    return booking_to_dict(booking)

@api_router.delete("/admin/bookings/{booking_id}")
async def admin_delete_booking(
    booking_id: str,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Delete a booking"""
    result = await db.execute(select(Booking).where(Booking.id == booking_id))
    booking = result.scalar_one_or_none()
    if not booking:
        raise HTTPException(status_code=404, detail="Booking not found")
    
    await db.delete(booking)
    await db.commit()
    
    logger.info(f"Booking {booking_id} deleted by {user.email}")
    return {"message": "Booking deleted successfully"}

# Admin - Users Management

# Admin - Reports
@api_router.get("/admin/reports/sales")
async def admin_get_sales_report(
    period: str = "daily",  # daily, weekly, monthly
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    now = datetime.now(timezone.utc)
    
    if start_date:
        start = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
    else:
        if period == "daily":
            start = now - timedelta(days=30)
        elif period == "weekly":
            start = now - timedelta(weeks=12)
        else:
            start = now - timedelta(days=365)
    
    if end_date:
        end = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
    else:
        end = now
    
    # Get orders in date range
    result = await db.execute(
        select(Order)
        .where(and_(Order.created_at >= start, Order.created_at <= end))
        .options(selectinload(Order.items))
        .order_by(Order.created_at)
    )
    orders = result.scalars().all()
    
    # Get bookings in date range
    bookings_result = await db.execute(
        select(Booking)
        .where(and_(Booking.created_at >= start, Booking.created_at <= end))
        .options(selectinload(Booking.service))
    )
    bookings = bookings_result.scalars().all()
    
    # Aggregate by period
    report_data = {}
    for order in orders:
        if period == "daily":
            key = order.created_at.strftime("%Y-%m-%d")
        elif period == "weekly":
            key = order.created_at.strftime("%Y-W%W")
        else:
            key = order.created_at.strftime("%Y-%m")
        
        if key not in report_data:
            report_data[key] = {
                "period": key,
                "orders": 0,
                "revenue": 0,
                "products_sold": 0,
                "order_statuses": {},
                "services_booked": 0,
                "services_completed": 0,
                "services_paid": 0,
                "service_revenue": 0
            }
        
        report_data[key]["orders"] += 1
        report_data[key]["revenue"] += order.total
        report_data[key]["products_sold"] += sum(item.quantity for item in order.items)
        
        status = order.status.value if order.status else "unknown"
        report_data[key]["order_statuses"][status] = report_data[key]["order_statuses"].get(status, 0) + 1
    
    # Add booking counts and service revenue
    total_service_revenue = 0
    total_services_completed = 0
    total_services_paid = 0
    
    for booking in bookings:
        if period == "daily":
            key = booking.created_at.strftime("%Y-%m-%d")
        elif period == "weekly":
            key = booking.created_at.strftime("%Y-W%W")
        else:
            key = booking.created_at.strftime("%Y-%m")
        
        if key not in report_data:
            report_data[key] = {
                "period": key,
                "orders": 0,
                "revenue": 0,
                "products_sold": 0,
                "order_statuses": {},
                "services_booked": 0,
                "services_completed": 0,
                "services_paid": 0,
                "service_revenue": 0
            }
        
        report_data[key]["services_booked"] = report_data[key].get("services_booked", 0) + 1
        
        if booking.status == "completed":
            report_data[key]["services_completed"] = report_data[key].get("services_completed", 0) + 1
            total_services_completed += 1
        
        if booking.paid:
            report_data[key]["services_paid"] = report_data[key].get("services_paid", 0) + 1
            total_services_paid += 1
            # Use service_cost if set, otherwise use service base price
            cost = booking.service_cost if booking.service_cost else (booking.service.price if booking.service else 0)
            report_data[key]["service_revenue"] = report_data[key].get("service_revenue", 0) + cost
            total_service_revenue += cost
    
    # Calculate totals
    total_orders = len(orders)
    total_revenue = sum(o.total for o in orders)
    total_products = sum(sum(item.quantity for item in o.items) for o in orders)
    total_bookings = len(bookings)
    
    return {
        "period": period,
        "start_date": start.isoformat(),
        "end_date": end.isoformat(),
        "summary": {
            "total_orders": total_orders,
            "total_revenue": total_revenue,
            "total_products_sold": total_products,
            "total_services_booked": total_bookings,
            "total_services_completed": total_services_completed,
            "total_services_paid": total_services_paid,
            "total_service_revenue": total_service_revenue,
            "combined_revenue": total_revenue + total_service_revenue,
            "average_order_value": total_revenue / total_orders if total_orders > 0 else 0
        },
        "data": list(report_data.values())
    }

# Admin - Export Reports
@api_router.get("/admin/reports/export/csv")
async def admin_export_csv(
    report_type: str = "sales",  # sales, inventory, orders
    period: str = "monthly",
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    output = io.StringIO()
    writer = csv.writer(output)
    
    now = datetime.now(timezone.utc)
    
    if report_type == "sales":
        if period == "daily":
            start = now - timedelta(days=30)
        elif period == "weekly":
            start = now - timedelta(weeks=12)
        else:
            start = now - timedelta(days=365)
        
        result = await db.execute(
            select(Order)
            .where(Order.created_at >= start)
            .options(selectinload(Order.items), selectinload(Order.user))
            .order_by(Order.created_at)
        )
        orders = result.scalars().all()
        
        writer.writerow(["Date", "Order ID", "Customer", "Items", "Subtotal", "Tax", "Shipping", "Total", "Status"])
        for order in orders:
            writer.writerow([
                order.created_at.strftime("%Y-%m-%d %H:%M"),
                order.id,
                order.user.name if order.user else "Guest",
                sum(item.quantity for item in order.items),
                f"${order.subtotal:.2f}",
                f"${order.tax:.2f}",
                f"${order.shipping:.2f}",
                f"${order.total:.2f}",
                order.status.value if order.status else "unknown"
            ])
    
    elif report_type == "inventory":
        result = await db.execute(select(Product).where(Product.is_active == True))
        products = result.scalars().all()
        
        writer.writerow(["Product ID", "Name", "Category", "Brand", "Price", "Stock", "Low Stock Threshold", "Status"])
        for product in products:
            writer.writerow([
                product.id,
                product.name,
                product.category,
                product.brand,
                f"${product.price:.2f}",
                product.stock,
                product.low_stock_threshold,
                "Low Stock" if product.stock <= product.low_stock_threshold else "In Stock"
            ])
    
    elif report_type == "orders":
        result = await db.execute(
            select(Order)
            .options(selectinload(Order.items), selectinload(Order.user))
            .order_by(desc(Order.created_at))
            .limit(500)
        )
        orders = result.scalars().all()
        
        writer.writerow(["Order ID", "Date", "Customer", "Email", "Items", "Total", "Status", "Tracking"])
        for order in orders:
            writer.writerow([
                order.id,
                order.created_at.strftime("%Y-%m-%d %H:%M"),
                order.user.name if order.user else "Guest",
                order.user.email if order.user else "",
                sum(item.quantity for item in order.items),
                f"${order.total:.2f}",
                order.status.value if order.status else "unknown",
                order.tracking_number or ""
            ])
    
    output.seek(0)
    return StreamingResponse(
        iter([output.getvalue()]),
        media_type="text/csv",
        headers={"Content-Disposition": f"attachment; filename={report_type}_report_{now.strftime('%Y%m%d')}.csv"}
    )

@api_router.get("/admin/reports/export/pdf")
async def admin_export_pdf(
    report_type: str = "sales",
    period: str = "monthly",
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    buffer = io.BytesIO()
    doc = SimpleDocTemplate(buffer, pagesize=A4)
    styles = getSampleStyleSheet()
    elements = []
    
    now = datetime.now(timezone.utc)
    
    # Title
    title_style = ParagraphStyle(
        'CustomTitle',
        parent=styles['Heading1'],
        fontSize=24,
        spaceAfter=30
    )
    elements.append(Paragraph(f"TechZone {report_type.title()} Report", title_style))
    elements.append(Paragraph(f"Generated: {now.strftime('%Y-%m-%d %H:%M')}", styles['Normal']))
    elements.append(Spacer(1, 20))
    
    if report_type == "sales":
        if period == "daily":
            start = now - timedelta(days=30)
        elif period == "weekly":
            start = now - timedelta(weeks=12)
        else:
            start = now - timedelta(days=365)
        
        result = await db.execute(
            select(Order)
            .where(Order.created_at >= start)
            .options(selectinload(Order.items))
        )
        orders = result.scalars().all()
        
        # Summary
        total_orders = len(orders)
        total_revenue = sum(o.total for o in orders)
        total_products = sum(sum(item.quantity for item in o.items) for o in orders)
        
        elements.append(Paragraph("Summary", styles['Heading2']))
        summary_data = [
            ["Metric", "Value"],
            ["Total Orders", str(total_orders)],
            ["Total Revenue", f"${total_revenue:.2f}"],
            ["Products Sold", str(total_products)],
            ["Average Order Value", f"${total_revenue/total_orders:.2f}" if total_orders > 0 else "$0.00"]
        ]
        summary_table = Table(summary_data, colWidths=[3*inch, 2*inch])
        summary_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, 0), 12),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
            ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
            ('GRID', (0, 0), (-1, -1), 1, colors.black)
        ]))
        elements.append(summary_table)
        elements.append(Spacer(1, 20))
        
        # Orders table
        elements.append(Paragraph("Recent Orders", styles['Heading2']))
        orders_data = [["Date", "Order ID", "Items", "Total", "Status"]]
        for order in orders[:50]:
            orders_data.append([
                order.created_at.strftime("%Y-%m-%d"),
                order.id[:8] + "...",
                str(sum(item.quantity for item in order.items)),
                f"${order.total:.2f}",
                order.status.value if order.status else "unknown"
            ])
        
        orders_table = Table(orders_data, colWidths=[1.2*inch, 1.2*inch, 0.8*inch, 1*inch, 1*inch])
        orders_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 9),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.black)
        ]))
        elements.append(orders_table)
    
    elif report_type == "inventory":
        result = await db.execute(select(Product).where(Product.is_active == True).order_by(Product.stock))
        products = result.scalars().all()
        
        elements.append(Paragraph("Inventory Status", styles['Heading2']))
        inv_data = [["Product", "Category", "Price", "Stock", "Status"]]
        for product in products:
            status = "LOW STOCK" if product.stock <= product.low_stock_threshold else "In Stock"
            inv_data.append([
                product.name[:30] + "..." if len(product.name) > 30 else product.name,
                product.category,
                f"${product.price:.2f}",
                str(product.stock),
                status
            ])
        
        inv_table = Table(inv_data, colWidths=[2*inch, 1*inch, 0.8*inch, 0.6*inch, 0.8*inch])
        inv_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.black)
        ]))
        elements.append(inv_table)
    
    doc.build(elements)
    buffer.seek(0)
    
    return StreamingResponse(
        buffer,
        media_type="application/pdf",
        headers={"Content-Disposition": f"attachment; filename={report_type}_report_{now.strftime('%Y%m%d')}.pdf"}
    )

# ================== USER MANAGEMENT ==================

class UserCreateAdmin(BaseModel):
    email: EmailStr
    name: str
    password: str
    role: str
    is_active: bool = True
    password_never_change: bool = False

class UserUpdateAdmin(BaseModel):
    email: Optional[EmailStr] = None
    name: Optional[str] = None
    password: Optional[str] = None  # Allow password updates
    role: Optional[str] = None
    is_active: Optional[bool] = None
    password_never_change: Optional[bool] = None

@api_router.get("/admin/users")
async def get_all_users(
    skip: int = 0,
    limit: int = 20,
    search: str = "",
    role: str = "",
    status: str = "",
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Get all users with filters"""
    query = select(User)
    
    # Apply search filter
    if search:
        query = query.where(
            or_(
                User.name.ilike(f"%{search}%"),
                User.email.ilike(f"%{search}%")
            )
        )
    
    # Apply role filter
    if role:
        try:
            role_enum = UserRole[role.upper()]
            query = query.where(User.role == role_enum)
        except KeyError:
            pass
    
    # Apply status filter
    if status == "active":
        query = query.where(User.is_active == True)
    elif status == "inactive":
        query = query.where(User.is_active == False)
    
    # Get total count
    count_result = await db.execute(select(func.count()).select_from(query.subquery()))
    total = count_result.scalar()
    
    # Apply pagination
    query = query.offset(skip).limit(limit).order_by(User.created_at.desc())
    result = await db.execute(query)
    users = result.scalars().all()
    
    return {
        "users": [user_to_dict(user) for user in users],
        "total": total,
        "skip": skip,
        "limit": limit
    }

@api_router.post("/admin/users")
async def create_user(
    user_data: UserCreateAdmin,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Create a new user (admin only)"""
    # Check if email already exists
    result = await db.execute(select(User).where(User.email == user_data.email))
    if result.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Email already registered")
    
    # Validate role
    try:
        role_enum = UserRole[user_data.role.upper()]
    except KeyError:
        raise HTTPException(status_code=400, detail=f"Invalid role: {user_data.role}")
    
    # Create new user
    hashed_password = await hash_password_async(user_data.password)
    new_user = User(
        email=user_data.email,
        name=user_data.name,
        password=hashed_password,
        role=role_enum,
        is_active=user_data.is_active
    )
    
    db.add(new_user)
    await db.commit()
    await db.refresh(new_user)
    
    logger.info(f"Admin {admin.email} created user {new_user.email} with role {role_enum.value}")
    
    return {
        "message": "User created successfully",
        "user": user_to_dict(new_user)
    }

@api_router.put("/admin/users/{user_id}")
async def update_user(
    user_id: str,
    user_data: UserUpdateAdmin,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Update user details (admin only)"""
    user = await _get_or_404(db, User, user_id, "User not found")
    
    # Update fields if provided
    if user_data.email is not None:
        # Check if new email already exists
        result = await db.execute(
            select(User).where(User.email == user_data.email, User.id != user_id)
        )
        if result.scalar_one_or_none():
            raise HTTPException(status_code=400, detail="Email already in use")
        user.email = user_data.email
    
    if user_data.name is not None:
        user.name = user_data.name
    
    if user_data.password is not None and user_data.password.strip():
        # Only update password if provided and not empty
        user.password = await hash_password_async(user_data.password)
    
    if user_data.role is not None:
        try:
            role_enum = UserRole[user_data.role.upper()]
            user.role = role_enum
        except KeyError:
            raise HTTPException(status_code=400, detail=f"Invalid role: {user_data.role}")
    
    if user_data.is_active is not None:
        user.is_active = user_data.is_active
    
    await db.commit()
    await db.refresh(user)
    
    logger.info(f"Admin {admin.email} updated user {user.email}")
    
    return {
        "message": "User updated successfully",
        "user": user_to_dict(user)
    }

@api_router.put("/admin/users/{user_id}/toggle-active")
async def toggle_user_active(
    user_id: str,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Toggle user active status"""
    user = await _get_or_404(db, User, user_id, "User not found")
    
    # Prevent deactivating yourself
    if user.id == admin.id:
        raise HTTPException(status_code=400, detail="Cannot deactivate your own account")
    
    user.is_active = not user.is_active
    await db.commit()
    await db.refresh(user)
    
    status = "activated" if user.is_active else "deactivated"
    logger.info(f"Admin {admin.email} {status} user {user.email}")
    
    return {
        "message": f"User {status} successfully",
        "user": user_to_dict(user)
    }

@api_router.delete("/admin/users/{user_id}")
async def delete_user(
    user_id: str,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Delete a user (admin only)"""
    user = await _get_or_404(db, User, user_id, "User not found")
    
    # Prevent deleting yourself
    if user.id == admin.id:
        raise HTTPException(status_code=400, detail="Cannot delete your own account")
    
    await db.delete(user)
    await db.commit()
    
    logger.info(f"Admin {admin.email} deleted user {user.email}")
    
    return {"message": "User deleted successfully"}

# ================== ABOUT PAGE CMS ==================

# Pydantic schemas for About page
class AboutContentCreate(BaseModel):
    section: str
    title: Optional[str] = None
    subtitle: Optional[str] = None
    content: Optional[str] = None
    image_url: Optional[str] = None
    data: Optional[dict] = None
    display_order: int = 0
    is_active: bool = True

class AboutContentUpdate(BaseModel):
    title: Optional[str] = None
    subtitle: Optional[str] = None
    content: Optional[str] = None
    image_url: Optional[str] = None
    data: Optional[dict] = None
    display_order: Optional[int] = None
    is_active: Optional[bool] = None

class TeamMemberCreate(BaseModel):
    name: str
    role: str
    bio: Optional[str] = None
    image_url: Optional[str] = None
    email: Optional[str] = None
    linkedin: Optional[str] = None
    display_order: int = 0
    is_active: bool = True

class TeamMemberUpdate(BaseModel):
    name: Optional[str] = None
    role: Optional[str] = None
    bio: Optional[str] = None
    image_url: Optional[str] = None
    email: Optional[str] = None
    linkedin: Optional[str] = None
    display_order: Optional[int] = None
    is_active: Optional[bool] = None

class CompanyValueCreate(BaseModel):
    title: str
    description: str
    icon: str
    display_order: int = 0
    is_active: bool = True

class CompanyValueUpdate(BaseModel):
    title: Optional[str] = None
    description: Optional[str] = None
    icon: Optional[str] = None
    display_order: Optional[int] = None
    is_active: Optional[bool] = None

# Public endpoints (no auth required)

@api_router.get("/about/content")
async def get_about_content(db: AsyncSession = Depends(get_db)):
    """Get all active about content sections"""
    result = await db.execute(
        select(AboutContent)
        .where(AboutContent.is_active == True)
        .order_by(AboutContent.section, AboutContent.display_order)
    )
    content = result.scalars().all()
    
    return [{
        "id": str(item.id),
        "section": item.section,
        "title": item.title,
        "subtitle": item.subtitle,
        "content": item.content,
        "image_url": item.image_url,
        "data": item.data,
        "display_order": item.display_order,
        "created_at": item.created_at.isoformat() if item.created_at else None,
        "updated_at": item.updated_at.isoformat() if item.updated_at else None
    } for item in content]

@api_router.get("/about/team")
async def get_team_members(db: AsyncSession = Depends(get_db)):
    """Get all active team members"""
    result = await db.execute(
        select(TeamMember)
        .where(TeamMember.is_active == True)
        .order_by(TeamMember.display_order)
    )
    members = result.scalars().all()
    
    return [{
        "id": str(member.id),
        "name": member.name,
        "role": member.role,
        "bio": member.bio,
        "image_url": member.image_url,
        "email": member.email,
        "linkedin": member.linkedin,
        "display_order": member.display_order
    } for member in members]

@api_router.get("/about/values")
async def get_company_values(db: AsyncSession = Depends(get_db)):
    """Get all active company values"""
    result = await db.execute(
        select(CompanyValue)
        .where(CompanyValue.is_active == True)
        .order_by(CompanyValue.display_order)
    )
    values = result.scalars().all()
    
    return [{
        "id": str(value.id),
        "title": value.title,
        "description": value.description,
        "icon": value.icon,
        "display_order": value.display_order
    } for value in values]

# Admin endpoints (auth required)

@api_router.get("/admin/about/content")
async def admin_get_all_about_content(
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Get all about content sections (including inactive)"""
    result = await db.execute(
        select(AboutContent).order_by(AboutContent.section, AboutContent.display_order)
    )
    content = result.scalars().all()
    
    return [{
        "id": str(item.id),
        "section": item.section,
        "title": item.title,
        "subtitle": item.subtitle,
        "content": item.content,
        "image_url": item.image_url,
        "data": item.data,
        "display_order": item.display_order,
        "is_active": item.is_active,
        "created_at": item.created_at.isoformat() if item.created_at else None,
        "updated_at": item.updated_at.isoformat() if item.updated_at else None
    } for item in content]

@api_router.post("/admin/about/content")
async def admin_create_about_content(
    content_data: AboutContentCreate,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Create new about content section"""
    content = AboutContent(
        section=content_data.section,
        title=content_data.title,
        subtitle=content_data.subtitle,
        content=content_data.content,
        image_url=content_data.image_url,
        data=content_data.data,
        display_order=content_data.display_order,
        is_active=content_data.is_active
    )
    
    db.add(content)
    await db.commit()
    await db.refresh(content)
    
    logger.info(f"Admin {admin.email} created about content section: {content.section}")
    
    return {
        "id": str(content.id),
        "section": content.section,
        "title": content.title,
        "subtitle": content.subtitle,
        "content": content.content,
        "image_url": content.image_url,
        "data": content.data,
        "display_order": content.display_order,
        "is_active": content.is_active,
        "created_at": content.created_at.isoformat() if content.created_at else None,
        "updated_at": content.updated_at.isoformat() if content.updated_at else None
    }

@api_router.put("/admin/about/content/{content_id}")
async def admin_update_about_content(
    content_id: str,
    content_data: AboutContentUpdate,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Update about content section"""
    result = await db.execute(select(AboutContent).where(AboutContent.id == content_id))
    content = result.scalar_one_or_none()
    
    if not content:
        raise HTTPException(status_code=404, detail="Content not found")
    
    # Update fields
    if content_data.title is not None:
        content.title = content_data.title
    if content_data.subtitle is not None:
        content.subtitle = content_data.subtitle
    if content_data.content is not None:
        content.content = content_data.content
    if content_data.image_url is not None:
        content.image_url = content_data.image_url
    if content_data.data is not None:
        content.data = content_data.data
    if content_data.display_order is not None:
        content.display_order = content_data.display_order
    if content_data.is_active is not None:
        content.is_active = content_data.is_active
    
    content.updated_at = datetime.utcnow()
    await db.commit()
    await db.refresh(content)
    
    logger.info(f"Admin {admin.email} updated about content: {content.section}")
    
    return {
        "id": str(content.id),
        "section": content.section,
        "title": content.title,
        "subtitle": content.subtitle,
        "content": content.content,
        "image_url": content.image_url,
        "data": content.data,
        "display_order": content.display_order,
        "is_active": content.is_active,
        "updated_at": content.updated_at.isoformat() if content.updated_at else None
    }

@api_router.delete("/admin/about/content/{content_id}")
async def admin_delete_about_content(
    content_id: str,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Delete about content section"""
    result = await db.execute(select(AboutContent).where(AboutContent.id == content_id))
    content = result.scalar_one_or_none()
    
    if not content:
        raise HTTPException(status_code=404, detail="Content not found")
    
    await db.delete(content)
    await db.commit()
    
    logger.info(f"Admin {admin.email} deleted about content: {content.section}")
    
    return {"message": "Content deleted successfully"}

# Team Members CRUD

@api_router.get("/admin/about/team")
async def admin_get_all_team_members(
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Get all team members (including inactive)"""
    result = await db.execute(
        select(TeamMember).order_by(TeamMember.display_order)
    )
    members = result.scalars().all()
    
    return [{
        "id": str(member.id),
        "name": member.name,
        "role": member.role,
        "bio": member.bio,
        "image_url": member.image_url,
        "email": member.email,
        "linkedin": member.linkedin,
        "display_order": member.display_order,
        "is_active": member.is_active,
        "created_at": member.created_at.isoformat() if member.created_at else None,
        "updated_at": member.updated_at.isoformat() if member.updated_at else None
    } for member in members]

@api_router.post("/admin/about/team")
async def admin_create_team_member(
    member_data: TeamMemberCreate,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Create new team member"""
    member = TeamMember(
        name=member_data.name,
        role=member_data.role,
        bio=member_data.bio,
        image_url=member_data.image_url,
        email=member_data.email,
        linkedin=member_data.linkedin,
        display_order=member_data.display_order,
        is_active=member_data.is_active
    )
    
    db.add(member)
    await db.commit()
    await db.refresh(member)
    
    logger.info(f"Admin {admin.email} created team member: {member.name}")
    
    return {
        "id": str(member.id),
        "name": member.name,
        "role": member.role,
        "bio": member.bio,
        "image_url": member.image_url,
        "email": member.email,
        "linkedin": member.linkedin,
        "display_order": member.display_order,
        "is_active": member.is_active,
        "created_at": member.created_at.isoformat() if member.created_at else None
    }

@api_router.put("/admin/about/team/{member_id}")
async def admin_update_team_member(
    member_id: str,
    member_data: TeamMemberUpdate,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Update team member"""
    result = await db.execute(select(TeamMember).where(TeamMember.id == member_id))
    member = result.scalar_one_or_none()
    
    if not member:
        raise HTTPException(status_code=404, detail="Team member not found")
    
    # Update fields
    if member_data.name is not None:
        member.name = member_data.name
    if member_data.role is not None:
        member.role = member_data.role
    if member_data.bio is not None:
        member.bio = member_data.bio
    if member_data.image_url is not None:
        member.image_url = member_data.image_url
    if member_data.email is not None:
        member.email = member_data.email
    if member_data.linkedin is not None:
        member.linkedin = member_data.linkedin
    if member_data.display_order is not None:
        member.display_order = member_data.display_order
    if member_data.is_active is not None:
        member.is_active = member_data.is_active
    
    member.updated_at = datetime.utcnow()
    await db.commit()
    await db.refresh(member)
    
    logger.info(f"Admin {admin.email} updated team member: {member.name}")
    
    return {
        "id": str(member.id),
        "name": member.name,
        "role": member.role,
        "bio": member.bio,
        "image_url": member.image_url,
        "email": member.email,
        "linkedin": member.linkedin,
        "display_order": member.display_order,
        "is_active": member.is_active,
        "updated_at": member.updated_at.isoformat() if member.updated_at else None
    }

@api_router.delete("/admin/about/team/{member_id}")
async def admin_delete_team_member(
    member_id: str,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Delete team member"""
    result = await db.execute(select(TeamMember).where(TeamMember.id == member_id))
    member = result.scalar_one_or_none()
    
    if not member:
        raise HTTPException(status_code=404, detail="Team member not found")
    
    await db.delete(member)
    await db.commit()
    
    logger.info(f"Admin {admin.email} deleted team member: {member.name}")
    
    return {"message": "Team member deleted successfully"}

# Company Values CRUD

@api_router.get("/admin/about/values")
async def admin_get_all_company_values(
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Get all company values (including inactive)"""
    result = await db.execute(
        select(CompanyValue).order_by(CompanyValue.display_order)
    )
    values = result.scalars().all()
    
    return [{
        "id": str(value.id),
        "title": value.title,
        "description": value.description,
        "icon": value.icon,
        "display_order": value.display_order,
        "is_active": value.is_active,
        "created_at": value.created_at.isoformat() if value.created_at else None,
        "updated_at": value.updated_at.isoformat() if value.updated_at else None
    } for value in values]

@api_router.post("/admin/about/values")
async def admin_create_company_value(
    value_data: CompanyValueCreate,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Create new company value"""
    value = CompanyValue(
        title=value_data.title,
        description=value_data.description,
        icon=value_data.icon,
        display_order=value_data.display_order,
        is_active=value_data.is_active
    )
    
    db.add(value)
    await db.commit()
    await db.refresh(value)
    
    logger.info(f"Admin {admin.email} created company value: {value.title}")
    
    return {
        "id": str(value.id),
        "title": value.title,
        "description": value.description,
        "icon": value.icon,
        "display_order": value.display_order,
        "is_active": value.is_active,
        "created_at": value.created_at.isoformat() if value.created_at else None
    }

@api_router.put("/admin/about/values/{value_id}")
async def admin_update_company_value(
    value_id: str,
    value_data: CompanyValueUpdate,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Update company value"""
    result = await db.execute(select(CompanyValue).where(CompanyValue.id == value_id))
    value = result.scalar_one_or_none()
    
    if not value:
        raise HTTPException(status_code=404, detail="Company value not found")
    
    # Update fields
    if value_data.title is not None:
        value.title = value_data.title
    if value_data.description is not None:
        value.description = value_data.description
    if value_data.icon is not None:
        value.icon = value_data.icon
    if value_data.display_order is not None:
        value.display_order = value_data.display_order
    if value_data.is_active is not None:
        value.is_active = value_data.is_active
    
    value.updated_at = datetime.utcnow()
    await db.commit()
    await db.refresh(value)
    
    logger.info(f"Admin {admin.email} updated company value: {value.title}")
    
    return {
        "id": str(value.id),
        "title": value.title,
        "description": value.description,
        "icon": value.icon,
        "display_order": value.display_order,
        "is_active": value.is_active,
        "updated_at": value.updated_at.isoformat() if value.updated_at else None
    }

@api_router.delete("/admin/about/values/{value_id}")
async def admin_delete_company_value(
    value_id: str,
    admin: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    """Delete company value"""
    result = await db.execute(select(CompanyValue).where(CompanyValue.id == value_id))
    value = result.scalar_one_or_none()
    
    if not value:
        raise HTTPException(status_code=404, detail="Company value not found")
    
    await db.delete(value)
    await db.commit()
    
    logger.info(f"Admin {admin.email} deleted company value: {value.title}")
    
    return {"message": "Company value deleted successfully"}

# ================== SEED DATA ==================

@api_router.post("/seed")
async def seed_data(db: AsyncSession = Depends(get_db)):
    # Check if data exists
    result = await db.execute(select(func.count(Product.id)))
    if result.scalar() > 0:
        return {"message": "Data already seeded"}
    
    # Create admin user
    admin_password = await hash_password_async("admin123")
    admin = User(
        email="admin@techzone.com",
        name="Admin",
        password=admin_password,
        role=UserRole.ADMIN
    )
    db.add(admin)
    
    # Create products
    products = [
        Product(name="MacBook Pro 16\"", description="Powerful laptop with M3 Pro chip, 18GB RAM, 512GB SSD.", price=2499.99, category="laptops", image_url="https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=800", stock=15, brand="Apple", specs={"processor": "M3 Pro", "ram": "18GB", "storage": "512GB SSD"}),
        Product(name="Dell XPS 15", description="Ultra-thin laptop with Intel Core i7, 16GB RAM, stunning OLED display.", price=1799.99, category="laptops", image_url="https://images.unsplash.com/photo-1593642632559-0c6d3fc62b89?w=800", stock=20, brand="Dell", specs={"processor": "Intel i7", "ram": "16GB", "storage": "512GB SSD"}),
        Product(name="iPhone 15 Pro Max", description="Latest iPhone with titanium design, A17 Pro chip, 48MP camera.", price=1199.99, category="phones", image_url="https://images.unsplash.com/photo-1695048133142-1a20484d2569?w=800", stock=30, brand="Apple", specs={"display": "6.7\" OLED", "camera": "48MP", "storage": "256GB"}),
        Product(name="Samsung Galaxy S24 Ultra", description="Premium Android phone with S Pen, 200MP camera, AI features.", price=1299.99, category="phones", image_url="https://images.unsplash.com/photo-1610945265064-0e34e5519bbf?w=800", stock=25, brand="Samsung", specs={"display": "6.8\" AMOLED", "camera": "200MP", "storage": "512GB"}),
        Product(name="Sony WH-1000XM5", description="Industry-leading noise cancellation, 30-hour battery.", price=349.99, category="accessories", image_url="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=800", stock=40, brand="Sony", specs={"type": "Over-ear", "battery": "30 hours"}),
        Product(name="iPad Pro 12.9\"", description="Powerful tablet with M2 chip, Liquid Retina XDR display.", price=1099.99, category="tablets", image_url="https://images.unsplash.com/photo-1544244015-0df4b3ffc6b0?w=800", stock=18, brand="Apple", specs={"processor": "M2", "display": "12.9\" XDR"}),
        Product(name="Apple Watch Ultra 2", description="Rugged smartwatch with titanium case, GPS, 36-hour battery.", price=799.99, category="wearables", image_url="https://images.unsplash.com/photo-1434493789847-2f02dc6ca35d?w=800", stock=22, brand="Apple", specs={"display": "49mm", "battery": "36 hours"}),
        Product(name="Logitech MX Master 3S", description="Premium wireless mouse with 8K DPI sensor, silent clicks.", price=99.99, category="accessories", image_url="https://images.unsplash.com/photo-1527864550417-7fd91fc51a46?w=800", stock=50, brand="Logitech", specs={"sensor": "8K DPI", "battery": "70 days"}),
    ]
    for p in products:
        db.add(p)
    
    # Create services
    services = [
        Service(name="Screen Repair", description="Professional screen replacement for phones, tablets, and laptops.", price=149.99, duration="1-2 hours", image_url="https://images.unsplash.com/photo-1581092918056-0c4c3acd3789?w=800", category="repair"),
        Service(name="Battery Replacement", description="Restore your device's battery life with genuine replacement.", price=79.99, duration="30-60 mins", image_url="https://images.unsplash.com/photo-1609091839311-d5365f9ff1c5?w=800", category="repair"),
        Service(name="Data Recovery", description="Professional data recovery from damaged drives.", price=199.99, duration="2-5 days", image_url="https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=800", category="data"),
        Service(name="Virus Removal", description="Complete malware and virus removal with system optimization.", price=89.99, duration="1-3 hours", image_url="https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?w=800", category="software"),
        Service(name="Hardware Upgrade", description="Upgrade your RAM, SSD, or other components.", price=49.99, duration="1-2 hours", image_url="https://images.unsplash.com/photo-1591799265444-d66432b91588?w=800", category="upgrade"),
        Service(name="Device Setup", description="Complete setup service for new devices including data transfer.", price=59.99, duration="1-2 hours", image_url="https://images.unsplash.com/photo-1531297484001-80022131f5a1?w=800", category="setup"),
    ]
    for s in services:
        db.add(s)
    
    await db.commit()
    return {"message": "Data seeded successfully"}

# ================== ROOT ==================

@api_router.get("/")
async def root():
    return {"message": "TechZone API is running", "version": "2.0.0", "status": "healthy"}

# ============================================
# MEDIA MANAGEMENT ENDPOINTS
# ============================================

def get_media_type(filename: str) -> MediaType:
    """Determine media type from file extension"""
    ext = Path(filename).suffix.lower()
    if ext in ALLOWED_IMAGE_EXTENSIONS:
        return MediaType.IMAGE
    elif ext in ALLOWED_DOC_EXTENSIONS:
        return MediaType.DOCUMENT
    elif ext in ALLOWED_VIDEO_EXTENSIONS:
        return MediaType.VIDEO
    return MediaType.OTHER


def get_image_dimensions(file_path: Path) -> tuple:
    """Get image dimensions if PIL is available"""
    try:
        from PIL import Image
        with Image.open(file_path) as img:
            return img.size
    except:
        return None, None


@api_router.get("/media")
async def get_all_media(
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    media_type: str = Query(None),
    search: str = Query(None),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Get all media files with pagination"""
    if current_user.role not in [UserRole.ADMIN, UserRole.EMPLOYEE]:
        raise HTTPException(status_code=403, detail="Not authorized")
    
    try:
        query = select(Media).where(Media.is_active == True)
        
        if media_type:
            query = query.where(Media.media_type == MediaType(media_type))
        
        if search:
            query = query.where(
                or_(
                    Media.original_filename.ilike(f"%{search}%"),
                    Media.title.ilike(f"%{search}%"),
                    Media.alt_text.ilike(f"%{search}%")
                )
            )
        
        # Get total count
        count_query = select(func.count(Media.id)).where(Media.is_active == True)
        if media_type:
            count_query = count_query.where(Media.media_type == MediaType(media_type))
        if search:
            count_query = count_query.where(
                or_(
                    Media.original_filename.ilike(f"%{search}%"),
                    Media.title.ilike(f"%{search}%")
                )
            )
        total_result = await db.execute(count_query)
        total = total_result.scalar()
        
        # Apply pagination
        offset = (page - 1) * limit
        query = query.order_by(Media.created_at.desc()).offset(offset).limit(limit)
        
        result = await db.execute(query)
        media_items = result.scalars().all()
        
        return {
            "items": [{
                "id": m.id,
                "filename": m.filename,
                "original_filename": m.original_filename,
                "file_url": m.file_url,
                "file_size": m.file_size,
                "mime_type": m.mime_type,
                "media_type": m.media_type.value,
                "alt_text": m.alt_text,
                "title": m.title,
                "width": m.width,
                "height": m.height,
                "created_at": m.created_at.isoformat() if m.created_at else None
            } for m in media_items],
            "total": total,
            "page": page,
            "limit": limit,
            "pages": (total + limit - 1) // limit
        }
    except Exception as e:
        logger.error(f"Error fetching media: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@api_router.post("/media/upload")
async def upload_media(
    file: UploadFile = File(...),
    alt_text: str = Form(None),
    title: str = Form(None),
    description: str = Form(None),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Upload a media file"""
    if current_user.role not in [UserRole.ADMIN, UserRole.EMPLOYEE]:
        raise HTTPException(status_code=403, detail="Not authorized")
    
    try:
        # Validate file
        if not file.filename:
            raise HTTPException(status_code=400, detail="No file provided")
        
        # Check file extension
        ext = Path(file.filename).suffix.lower()
        all_allowed = ALLOWED_IMAGE_EXTENSIONS | ALLOWED_DOC_EXTENSIONS | ALLOWED_VIDEO_EXTENSIONS
        if ext not in all_allowed:
            raise HTTPException(
                status_code=400, 
                detail=f"File type not allowed. Allowed: {', '.join(all_allowed)}"
            )
        
        # Read file content
        content = await file.read()
        file_size = len(content)
        
        # Check file size
        if file_size > MAX_FILE_SIZE:
            raise HTTPException(
                status_code=400, 
                detail=f"File too large. Maximum size: {MAX_FILE_SIZE // (1024*1024)}MB"
            )
        
        # Generate unique filename
        unique_filename = f"{uuid.uuid4()}{ext}"
        file_path = MEDIA_UPLOAD_DIR / unique_filename
        
        # Save file
        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(content)
        
        # Get image dimensions if applicable
        width, height = None, None
        if ext in ALLOWED_IMAGE_EXTENSIONS:
            width, height = get_image_dimensions(file_path)
        
        # Determine media type
        media_type = get_media_type(file.filename)
        
        # Create media record
        media = Media(
            filename=unique_filename,
            original_filename=file.filename,
            file_path=str(file_path),
            file_url=f"/uploads/media/{unique_filename}",
            file_size=file_size,
            mime_type=file.content_type,
            media_type=media_type,
            alt_text=alt_text or file.filename,
            title=title or Path(file.filename).stem,
            description=description,
            width=width,
            height=height,
            uploaded_by=current_user.id
        )
        
        db.add(media)
        await db.commit()
        await db.refresh(media)
        
        logger.info(f"Media uploaded: {unique_filename} by {current_user.email}")
        
        return {
            "id": media.id,
            "filename": media.filename,
            "original_filename": media.original_filename,
            "file_url": media.file_url,
            "file_size": media.file_size,
            "mime_type": media.mime_type,
            "media_type": media.media_type.value,
            "alt_text": media.alt_text,
            "title": media.title,
            "width": media.width,
            "height": media.height,
            "created_at": media.created_at.isoformat() if media.created_at else None
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error uploading media: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@api_router.post("/media/upload-multiple")
async def upload_multiple_media(
    files: List[UploadFile] = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Upload multiple media files at once"""
    if current_user.role not in [UserRole.ADMIN, UserRole.EMPLOYEE]:
        raise HTTPException(status_code=403, detail="Not authorized")
    
    uploaded = []
    errors = []
    
    for file in files:
        try:
            if not file.filename:
                continue
            
            ext = Path(file.filename).suffix.lower()
            all_allowed = ALLOWED_IMAGE_EXTENSIONS | ALLOWED_DOC_EXTENSIONS | ALLOWED_VIDEO_EXTENSIONS
            if ext not in all_allowed:
                errors.append({"filename": file.filename, "error": "File type not allowed"})
                continue
            
            content = await file.read()
            file_size = len(content)
            
            if file_size > MAX_FILE_SIZE:
                errors.append({"filename": file.filename, "error": "File too large"})
                continue
            
            unique_filename = f"{uuid.uuid4()}{ext}"
            file_path = MEDIA_UPLOAD_DIR / unique_filename
            
            async with aiofiles.open(file_path, 'wb') as f:
                await f.write(content)
            
            width, height = None, None
            if ext in ALLOWED_IMAGE_EXTENSIONS:
                width, height = get_image_dimensions(file_path)
            
            media_type = get_media_type(file.filename)
            
            media = Media(
                filename=unique_filename,
                original_filename=file.filename,
                file_path=str(file_path),
                file_url=f"/uploads/media/{unique_filename}",
                file_size=file_size,
                mime_type=file.content_type,
                media_type=media_type,
                alt_text=file.filename,
                title=Path(file.filename).stem,
                width=width,
                height=height,
                uploaded_by=current_user.id
            )
            
            db.add(media)
            uploaded.append({
                "filename": file.filename,
                "file_url": media.file_url
            })
        except Exception as e:
            errors.append({"filename": file.filename, "error": str(e)})
    
    await db.commit()
    
    return {
        "uploaded": uploaded,
        "errors": errors,
        "total_uploaded": len(uploaded),
        "total_errors": len(errors)
    }


@api_router.get("/media/{media_id}")
async def get_media(
    media_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Get a single media item"""
    if current_user.role not in [UserRole.ADMIN, UserRole.EMPLOYEE]:
        raise HTTPException(status_code=403, detail="Not authorized")
    
    result = await db.execute(select(Media).where(Media.id == media_id))
    media = result.scalar_one_or_none()
    
    if not media:
        raise HTTPException(status_code=404, detail="Media not found")
    
    return {
        "id": media.id,
        "filename": media.filename,
        "original_filename": media.original_filename,
        "file_url": media.file_url,
        "file_size": media.file_size,
        "mime_type": media.mime_type,
        "media_type": media.media_type.value,
        "alt_text": media.alt_text,
        "title": media.title,
        "description": media.description,
        "width": media.width,
        "height": media.height,
        "created_at": media.created_at.isoformat() if media.created_at else None
    }


@api_router.put("/media/{media_id}")
async def update_media(
    media_id: str,
    alt_text: str = Form(None),
    title: str = Form(None),
    description: str = Form(None),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Update media metadata"""
    if current_user.role not in [UserRole.ADMIN, UserRole.EMPLOYEE]:
        raise HTTPException(status_code=403, detail="Not authorized")
    
    result = await db.execute(select(Media).where(Media.id == media_id))
    media = result.scalar_one_or_none()
    
    if not media:
        raise HTTPException(status_code=404, detail="Media not found")
    
    if alt_text is not None:
        media.alt_text = alt_text
    if title is not None:
        media.title = title
    if description is not None:
        media.description = description
    
    await db.commit()
    await db.refresh(media)
    
    return {
        "id": media.id,
        "filename": media.filename,
        "file_url": media.file_url,
        "alt_text": media.alt_text,
        "title": media.title,
        "description": media.description
    }


@api_router.delete("/media/{media_id}")
async def delete_media(
    media_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Delete a media file"""
    if current_user.role != UserRole.ADMIN:
        raise HTTPException(status_code=403, detail="Admin access required")
    
    result = await db.execute(select(Media).where(Media.id == media_id))
    media = result.scalar_one_or_none()
    
    if not media:
        raise HTTPException(status_code=404, detail="Media not found")
    
    # Delete physical file
    try:
        file_path = Path(media.file_path)
        if file_path.exists():
            file_path.unlink()
    except Exception as e:
        logger.warning(f"Could not delete file {media.file_path}: {e}")
    
    # Delete from database
    await db.delete(media)
    await db.commit()
    
    logger.info(f"Media deleted: {media.filename} by {current_user.email}")
    
    return {"message": "Media deleted successfully"}


@api_router.get("/health")
async def health_check(db: AsyncSession = Depends(get_db)):
    """Comprehensive health check endpoint"""
    try:
        # Test database connection
        result = await db.execute(select(func.count(User.id)))
        user_count = result.scalar()
        
        return {
            "status": "healthy",
            "database": "connected",
            "api_version": "2.0.0",
            "timestamp": datetime.now(timezone.utc).isoformat()
        }
    except Exception as e:
        logger.error(f"Health check failed: {e}")
        return {
            "status": "degraded",
            "database": "error",
            "error": str(e),
            "timestamp": datetime.now(timezone.utc).isoformat()
        }

# Add CORS middleware BEFORE including routes
app.add_middleware(
    CORSMiddleware,
    allow_credentials=True,
    allow_origins=["http://localhost:5300", "http://localhost:3000", "http://127.0.0.1:5300", "http://prompttech.dynns.com"],
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
    allow_headers=["*"],
    expose_headers=["*"],
)

# Include the router
app.include_router(api_router)

# Mount static files for uploaded images
app.mount("/uploads", StaticFiles(directory=str(ROOT_DIR / "uploads")), name="uploads")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8181)
