from typing import List, Optional
from uuid import UUID
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, desc

from app.database import get_db
from app.core.permissions import UserRole
from app.models.user import User
from app.models.device import Device
from app.models.reading import DeviceReading
from app.schemas.device import DeviceCreate, DeviceUpdate, DeviceResponse, DeviceReadingsResponse, DeviceReading as DeviceReadingSchema
from app.schemas.common import PaginatedResponse, MessageResponse
from app.api.deps import get_current_user, require_permission

router = APIRouter()


@router.get("", response_model=PaginatedResponse[DeviceResponse])
async def list_devices(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    device_type: Optional[str] = None,
    is_online: Optional[bool] = None,
    location: Optional[str] = None,
    current_user: User = Depends(require_permission("devices:read")),
    db: AsyncSession = Depends(get_db)
):
    """قائمة الأجهزة"""
    query = select(Device)
    
    # Filter by tenant
    if current_user.role != UserRole.SUPER_ADMIN.value:
        query = query.where(Device.tenant_id == current_user.tenant_id)
    
    # Apply filters
    if device_type:
        query = query.where(Device.device_type == device_type)
    if is_online is not None:
        query = query.where(Device.is_online == is_online)
    if location:
        query = query.where(Device.location.ilike(f"%{location}%"))
    
    # Count total
    count_query = select(func.count()).select_from(query.subquery())
    total = await db.scalar(count_query)
    
    # Paginate
    query = query.order_by(desc(Device.created_at)).offset((page - 1) * page_size).limit(page_size)
    result = await db.execute(query)
    devices = result.scalars().all()
    
    # Get latest readings for each device
    device_responses = []
    for device in devices:
        latest_readings = {}
        readings_result = await db.execute(
            select(DeviceReading)
            .where(DeviceReading.device_id == device.id)
            .order_by(desc(DeviceReading.recorded_at))
            .limit(5)
        )
        for reading in readings_result.scalars():
            if reading.reading_type not in latest_readings:
                latest_readings[reading.reading_type] = {
                    "value": float(reading.value),
                    "unit": reading.unit,
                    "recorded_at": reading.recorded_at.isoformat()
                }
        
        device_dict = {**device.__dict__, "latest_readings": latest_readings}
        device_responses.append(DeviceResponse(**device_dict))
    
    return PaginatedResponse(
        items=device_responses,
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.post("", response_model=DeviceResponse, status_code=status.HTTP_201_CREATED)
async def create_device(
    device_data: DeviceCreate,
    current_user: User = Depends(require_permission("devices:write")),
    db: AsyncSession = Depends(get_db)
):
    """إضافة جهاز جديد"""
    # Validate tenant access
    tenant_id = device_data.tenant_id
    if current_user.role != UserRole.SUPER_ADMIN.value:
        tenant_id = current_user.tenant_id
    
    # Check if device already exists for this tenant
    result = await db.execute(
        select(Device).where(
            Device.tenant_id == tenant_id,
            Device.lifesmart_device_id == device_data.lifesmart_device_id
        )
    )
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Device already exists for this tenant"
        )
    
    device = Device(
        tenant_id=tenant_id,
        lifesmart_device_id=device_data.lifesmart_device_id,
        lifesmart_hub_id=device_data.lifesmart_hub_id,
        name=device_data.name,
        name_ar=device_data.name_ar,
        device_type=device_data.device_type,
        device_model=device_data.device_model,
        location=device_data.location,
        location_ar=device_data.location_ar,
        icon=device_data.icon,
        metadata=device_data.metadata or {},
    )
    
    db.add(device)
    await db.commit()
    await db.refresh(device)
    
    return DeviceResponse(**device.__dict__, latest_readings={})


@router.get("/{device_id}", response_model=DeviceResponse)
async def get_device(
    device_id: UUID,
    current_user: User = Depends(require_permission("devices:read")),
    db: AsyncSession = Depends(get_db)
):
    """الحصول على جهاز محدد"""
    query = select(Device).where(Device.id == device_id)
    
    if current_user.role != UserRole.SUPER_ADMIN.value:
        query = query.where(Device.tenant_id == current_user.tenant_id)
    
    result = await db.execute(query)
    device = result.scalar_one_or_none()
    
    if device is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Device not found"
        )
    
    # Get latest readings
    latest_readings = {}
    readings_result = await db.execute(
        select(DeviceReading)
        .where(DeviceReading.device_id == device.id)
        .order_by(desc(DeviceReading.recorded_at))
        .limit(10)
    )
    for reading in readings_result.scalars():
        if reading.reading_type not in latest_readings:
            latest_readings[reading.reading_type] = {
                "value": float(reading.value),
                "unit": reading.unit,
                "recorded_at": reading.recorded_at.isoformat()
            }
    
    return DeviceResponse(**device.__dict__, latest_readings=latest_readings)


@router.patch("/{device_id}", response_model=DeviceResponse)
async def update_device(
    device_id: UUID,
    device_data: DeviceUpdate,
    current_user: User = Depends(require_permission("devices:write")),
    db: AsyncSession = Depends(get_db)
):
    """تحديث جهاز"""
    query = select(Device).where(Device.id == device_id)
    
    if current_user.role != UserRole.SUPER_ADMIN.value:
        query = query.where(Device.tenant_id == current_user.tenant_id)
    
    result = await db.execute(query)
    device = result.scalar_one_or_none()
    
    if device is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Device not found"
        )
    
    update_data = device_data.model_dump(exclude_unset=True)
    for field, value in update_data.items():
        setattr(device, field, value)
    
    await db.commit()
    await db.refresh(device)
    
    return DeviceResponse(**device.__dict__, latest_readings={})


@router.delete("/{device_id}", response_model=MessageResponse)
async def delete_device(
    device_id: UUID,
    current_user: User = Depends(require_permission("devices:delete")),
    db: AsyncSession = Depends(get_db)
):
    """حذف جهاز"""
    query = select(Device).where(Device.id == device_id)
    
    if current_user.role != UserRole.SUPER_ADMIN.value:
        query = query.where(Device.tenant_id == current_user.tenant_id)
    
    result = await db.execute(query)
    device = result.scalar_one_or_none()
    
    if device is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Device not found"
        )
    
    await db.delete(device)
    await db.commit()
    
    return MessageResponse(
        message="Device deleted successfully",
        message_ar="تم حذف الجهاز بنجاح"
    )


@router.get("/{device_id}/readings", response_model=DeviceReadingsResponse)
async def get_device_readings(
    device_id: UUID,
    period: str = Query("last_day", regex="^(last_hour|last_day|last_week|last_month)$"),
    reading_type: Optional[str] = None,
    current_user: User = Depends(require_permission("devices:read")),
    db: AsyncSession = Depends(get_db)
):
    """الحصول على قراءات جهاز"""
    # Verify access
    query = select(Device).where(Device.id == device_id)
    if current_user.role != UserRole.SUPER_ADMIN.value:
        query = query.where(Device.tenant_id == current_user.tenant_id)
    
    result = await db.execute(query)
    device = result.scalar_one_or_none()
    
    if device is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Device not found"
        )
    
    # Calculate time range
    now = datetime.utcnow()
    period_map = {
        "last_hour": timedelta(hours=1),
        "last_day": timedelta(days=1),
        "last_week": timedelta(weeks=1),
        "last_month": timedelta(days=30),
    }
    start_time = now - period_map[period]
    
    # Query readings
    readings_query = select(DeviceReading).where(
        DeviceReading.device_id == device_id,
        DeviceReading.recorded_at >= start_time
    )
    
    if reading_type:
        readings_query = readings_query.where(DeviceReading.reading_type == reading_type)
    
    readings_query = readings_query.order_by(DeviceReading.recorded_at)
    readings_result = await db.execute(readings_query)
    readings = readings_result.scalars().all()
    
    return DeviceReadingsResponse(
        device_id=device_id,
        readings=[DeviceReadingSchema(
            reading_type=r.reading_type,
            value=float(r.value),
            unit=r.unit,
            recorded_at=r.recorded_at
        ) for r in readings],
        period=period
    )
