"""System API endpoints.

Refactored to use services for business logic.
Session management uses PM3Service, system operations use SystemService.
"""
from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel
from typing import Optional, Dict

from ..services.container import container
from ..managers.ups_manager import get_ups_manager
from ..managers.ble_manager import get_ble_manager

router = APIRouter()


class CreateSessionRequest(BaseModel):
    force_takeover: bool = False
    device_id: Optional[str] = None  # Device to create session for


class CreateSessionResponse(BaseModel):
    success: bool
    session_id: Optional[str] = None
    device_id: Optional[str] = None
    error: Optional[str] = None


class SessionInfo(BaseModel):
    session_id: str
    device_id: Optional[str]
    client_ip: str
    created_at: float
    last_activity: float
    time_remaining: float


class CPUCoreInfo(BaseModel):
    """Per-core CPU information."""
    core_id: int
    percent: float
    online: bool = True  # Whether this core is currently enabled


class CPUInfo(BaseModel):
    """CPU information including per-core data."""
    count: int
    percent: float
    temperature: Optional[float] = None
    per_core: list[CPUCoreInfo] = []
    load_average: Optional[list[float]] = None


class SystemInfo(BaseModel):
    """System information response."""
    hostname: str
    uptime: float
    cpu_temp: Optional[float]
    cpu: Optional[CPUInfo] = None
    memory_used: float
    memory_total: float
    disk_used: float
    disk_total: float


@router.post("/session/create", response_model=CreateSessionResponse)
async def create_session(request: Request, body: CreateSessionRequest):
    """Create a new session for PM3 access.

    Uses PM3Service for session management.
    Optionally specify device_id for multi-device support.
    """
    # Get client IP from request
    client_ip = request.client.host if request.client else "unknown"
    user_agent = request.headers.get("user-agent")

    result = await container.pm3_service.create_session(
        client_ip=client_ip,
        user_agent=user_agent,
        force_takeover=body.force_takeover,
        device_id=body.device_id
    )

    if result.success:
        return CreateSessionResponse(
            success=True,
            session_id=result.data["session_id"],
            device_id=result.data.get("device_id"),
            error=None
        )
    else:
        return CreateSessionResponse(
            success=False,
            session_id=None,
            device_id=None,
            error=result.error.message
        )


@router.post("/session/{session_id}/release")
async def release_session(session_id: str, device_id: Optional[str] = None):
    """Release an active session.

    Uses PM3Service for session management.

    Args:
        session_id: Session ID to release
        device_id: Optional device ID for faster lookup
    """
    result = await container.pm3_service.release_session(session_id, device_id)

    if not result.success:
        raise HTTPException(
            status_code=404,
            detail=result.error.message
        )

    return {"success": True, "message": result.data["message"]}


@router.get("/session/active", response_model=Optional[SessionInfo])
async def get_active_session(device_id: Optional[str] = None):
    """Get information about the active session for a device.

    Uses PM3Service (via SessionManager) for session info.

    Args:
        device_id: Optional device ID. If None, returns any active session.
    """
    # Access session manager through container for consistency
    session = container.session_manager.get_active_session(device_id)

    if not session:
        return None

    import time
    from .. import config

    time_remaining = config.SESSION_TIMEOUT - (time.time() - session.last_activity)

    return SessionInfo(
        session_id=session.session_id,
        device_id=session.device_id,
        client_ip=session.client_ip,
        created_at=session.created_at,
        last_activity=session.last_activity,
        time_remaining=max(0, time_remaining)
    )


@router.get("/sessions/all")
async def get_all_sessions():
    """Get all active sessions across all devices.

    Returns a list of all active sessions with their device IDs.
    """
    result = container.pm3_service.get_all_sessions()
    return result.data


@router.get("/info", response_model=SystemInfo)
async def get_system_info():
    """Get system information.

    Refactored to use SystemService for business logic.
    """
    from ..services.container import container

    result = await container.system_service.get_info()

    if not result.success:
        raise HTTPException(
            status_code=500,
            detail=result.error.message
        )

    cpu_data = result.data["cpu"]
    memory_data = result.data["memory"]
    disk_data = result.data["disk"]

    # Build per-core CPU info
    per_core = [
        CPUCoreInfo(
            core_id=c["core_id"],
            percent=c["percent"],
            online=c.get("online", True)
        )
        for c in cpu_data.get("per_core", [])
    ]

    cpu_info = CPUInfo(
        count=cpu_data.get("count", 0),
        percent=cpu_data.get("percent", 0.0),
        temperature=cpu_data.get("temperature"),
        per_core=per_core,
        load_average=cpu_data.get("load_average")
    )

    return SystemInfo(
        hostname=result.data["hostname"],
        uptime=result.data["uptime"],
        cpu_temp=cpu_data.get("temperature"),
        cpu=cpu_info,
        memory_used=memory_data["used"],
        memory_total=memory_data["total"],
        disk_used=disk_data["used"],
        disk_total=disk_data["total"]
    )


@router.get("/config")
async def get_config():
    """Get system configuration (non-sensitive values)."""
    from .. import config

    return {
        "pm3_device": config.PM3_DEVICE,
        "session_timeout": config.SESSION_TIMEOUT,
        "wifi_mode": "auto",  # TODO: Get from wifi manager
        "ble_enabled": config.BLE_ENABLED,
        "auth_enabled": config.AUTH_ENABLED,
        "https_enabled": config.HTTPS_ENABLED
    }


@router.post("/restart")
async def restart_system(delay: int = 0):
    """Restart the system.

    Refactored to use SystemService for business logic.

    Args:
        delay: Delay in seconds before restart (default: 0)
    """
    from ..services.container import container

    result = await container.system_service.restart(delay=delay)

    if not result.success:
        raise HTTPException(
            status_code=500,
            detail=result.error.message
        )

    return {"success": True, "message": result.data["message"]}


@router.post("/shutdown")
async def shutdown_system(delay: int = 0):
    """Initiate system shutdown.

    Refactored to use SystemService for business logic.

    Args:
        delay: Delay in seconds before shutdown (default: 0)
    """
    from ..services.container import container

    result = await container.system_service.shutdown(delay=delay)

    if not result.success:
        raise HTTPException(
            status_code=500,
            detail=result.error.message
        )

    return {"success": True, "message": result.data["message"]}


class UPSStatusResponse(BaseModel):
    """UPS status response model."""
    battery_percentage: float
    voltage: float
    current: float
    power_source: str
    battery_status: str
    time_remaining: Optional[int] = None
    temperature: Optional[float] = None
    last_updated: Optional[str] = None
    is_available: bool
    error_message: Optional[str] = None


class UPSThresholdsRequest(BaseModel):
    """Request to set UPS battery thresholds."""
    shutdown_threshold: Optional[float] = None
    warning_threshold: Optional[float] = None


class PowerRestrictionsResponse(BaseModel):
    """Power restrictions response model."""
    restricted: bool
    reason: Optional[str] = None
    power_source: str
    ups_available: bool
    battery_percentage: Optional[float] = None
    allow_firmware_flash: bool
    allow_bootloader_flash: bool
    allow_intensive_operations: bool
    message: Optional[str] = None
    warning: Optional[str] = None
    shutdown_imminent: Optional[bool] = None


@router.get("/ups/status", response_model=UPSStatusResponse)
async def get_ups_status():
    """Get current UPS battery status."""
    ups_manager = get_ups_manager()
    status = await ups_manager.get_status()

    return UPSStatusResponse(
        battery_percentage=status.battery_percentage,
        voltage=status.voltage,
        current=status.current,
        power_source=status.power_source.value,
        battery_status=status.battery_status.value,
        time_remaining=status.time_remaining,
        temperature=status.temperature,
        last_updated=status.last_updated,
        is_available=status.is_available,
        error_message=status.error_message
    )


@router.post("/ups/thresholds")
async def set_ups_thresholds(request: UPSThresholdsRequest):
    """Set UPS battery thresholds for warnings and shutdown."""
    ups_manager = get_ups_manager()

    if request.shutdown_threshold is not None:
        ups_manager.set_shutdown_threshold(request.shutdown_threshold)

    if request.warning_threshold is not None:
        ups_manager.set_warning_threshold(request.warning_threshold)

    return {
        "success": True,
        "message": "UPS thresholds updated"
    }


@router.post("/ups/shutdown")
async def trigger_ups_shutdown(delay: int = 30):
    """Trigger safe shutdown via UPS manager.

    Args:
        delay: Delay in seconds before shutdown (default: 30)
    """
    ups_manager = get_ups_manager()
    await ups_manager.shutdown_device(delay=delay)

    return {
        "success": True,
        "message": f"Shutdown initiated with {delay}s delay"
    }


@router.get("/power/restrictions", response_model=PowerRestrictionsResponse)
async def get_power_restrictions():
    """Get current power restrictions based on UPS/battery state.

    Returns power policy information including:
    - Whether operations are restricted
    - Current power source (AC, battery, or assumed AC if no UPS)
    - Battery level (if UPS present)
    - Which operations are allowed (firmware flash, bootloader flash, etc.)
    - User-friendly messages and warnings

    This endpoint is critical for determining whether power-intensive
    operations (like firmware flashing) should be allowed.

    If UPS hardware is not detected, assumes stable AC power and allows
    all operations (user responsibility to ensure power stability).
    """
    ups_manager = get_ups_manager()
    restrictions = ups_manager.get_power_restrictions()

    return PowerRestrictionsResponse(**restrictions)


class PiModelResponse(BaseModel):
    """Pi model information response."""
    model: str
    model_short: str
    total_cores: int
    default_active_cores: int
    min_cores: int
    max_cores: int


class CPUCoresConfigResponse(BaseModel):
    """CPU cores configuration response."""
    total_cores: int
    online_cores: int
    configured_cores: Optional[int] = None  # From cmdline.txt maxcpus parameter
    configurable_cores: list[int]
    pi_model: Optional[PiModelResponse] = None


class SetCPUCoresRequest(BaseModel):
    """Request to set CPU cores."""
    num_cores: int
    persist: bool = True  # Save to config for boot persistence
    reboot: bool = True   # Reboot after saving


@router.get("/cpu/cores", response_model=CPUCoresConfigResponse)
async def get_cpu_cores():
    """Get CPU cores configuration.

    Returns information about:
    - Total physical cores
    - Currently online cores
    - Which cores can be toggled (core 0 is always on)
    - Pi model information with recommended defaults
    """
    result = await container.system_service.get_cpu_cores_config()

    if not result.success:
        raise HTTPException(
            status_code=500,
            detail=result.error.message
        )

    # Convert pi_model dict to response model if present
    pi_model_data = result.data.get("pi_model")
    pi_model = None
    if pi_model_data:
        pi_model = PiModelResponse(**pi_model_data)

    return CPUCoresConfigResponse(
        total_cores=result.data["total_cores"],
        online_cores=result.data["online_cores"],
        configured_cores=result.data.get("configured_cores"),
        configurable_cores=result.data["configurable_cores"],
        pi_model=pi_model
    )


@router.post("/cpu/cores")
async def set_cpu_cores(request: SetCPUCoresRequest):
    """Set the number of active CPU cores.

    Core 0 is always active. This endpoint enables/disables cores 1 through N.

    For Pi Zero 2 W, the recommended default is 2 cores (out of 4) for
    better thermal management and power efficiency.

    Args:
        num_cores: Number of cores to keep active (1 to max_cores)
        persist: Save setting to config file (default: True)
        reboot: Reboot system after saving (default: True)
    """
    result = await container.system_service.set_cpu_cores(
        num_cores=request.num_cores,
        persist=request.persist,
        reboot=request.reboot
    )

    if not result.success:
        raise HTTPException(
            status_code=400 if result.error.code == "invalid_cores" else 500,
            detail=result.error.message
        )

    return {
        "success": True,
        "message": result.data["message"],
        "requested": result.data.get("requested"),
        "actual": result.data.get("actual"),
        "rebooting": result.data.get("rebooting", False)
    }


@router.get("/pi/model", response_model=PiModelResponse)
async def get_pi_model():
    """Get Raspberry Pi model information.

    Returns the detected Pi model with recommended CPU core settings.
    """
    result = await container.system_service.get_pi_model()

    if not result.success:
        raise HTTPException(
            status_code=500,
            detail=result.error.message
        )

    return PiModelResponse(**result.data)


class BLEStatusResponse(BaseModel):
    """BLE status response model."""
    enabled: bool
    available: bool
    advertising: bool
    connected_devices: int
    device_name: str
    queued_notifications: int


class SendNotificationRequest(BaseModel):
    """Request to send a BLE notification."""
    type: str
    message: str
    data: Optional[Dict] = None


@router.get("/ble/status", response_model=BLEStatusResponse)
async def get_ble_status():
    """Get BLE manager status."""
    ble_manager = get_ble_manager()
    status = await ble_manager.get_status()

    return BLEStatusResponse(**status)


@router.post("/ble/advertising/start")
async def start_ble_advertising():
    """Start BLE advertising."""
    ble_manager = get_ble_manager()

    if not ble_manager.is_available():
        raise HTTPException(status_code=503, detail="BLE not available")

    await ble_manager.start_advertising()

    return {
        "success": True,
        "message": "BLE advertising started"
    }


@router.post("/ble/advertising/stop")
async def stop_ble_advertising():
    """Stop BLE advertising."""
    ble_manager = get_ble_manager()
    await ble_manager.stop_advertising()

    return {
        "success": True,
        "message": "BLE advertising stopped"
    }


@router.post("/ble/notify")
async def send_ble_notification(request: SendNotificationRequest):
    """Send a BLE notification to connected devices."""
    ble_manager = get_ble_manager()

    if not ble_manager.is_available():
        raise HTTPException(status_code=503, detail="BLE not available")

    from ..managers.ble_manager import NotificationType

    # Validate notification type
    try:
        notification_type = NotificationType(request.type)
    except ValueError:
        raise HTTPException(status_code=400, detail=f"Invalid notification type: {request.type}")

    await ble_manager.send_notification(
        notification_type=notification_type,
        message=request.message,
        data=request.data
    )

    return {
        "success": True,
        "message": "Notification sent"
    }
