"""
Hardware monitoring and control API endpoints.
"""

import logging
from typing import Dict, Any, List, Optional

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from ...hardware.hardware_manager import hardware_manager


logger = logging.getLogger(__name__)

router = APIRouter()


class TemperatureReading(BaseModel):
    """Temperature reading response model."""
    value: float
    sensor_name: str
    timestamp: str
    units: str = "°C"
    is_valid: bool = True
    error_message: Optional[str] = None


class MotorStatus(BaseModel):
    """Motor status response model."""
    name: str
    state: str
    is_enabled: bool
    current: Optional[float] = None
    runtime_hours: float = 0.0
    error_count: int = 0


class SafetyStatus(BaseModel):
    """Safety status response model."""
    emergency_stop_active: bool = False
    cover_sensor_closed: bool = True
    temperature_alarms: List[str] = []
    current_alarms: List[str] = []
    last_safety_check: Optional[str] = None


class HardwareStatusResponse(BaseModel):
    """Complete hardware status response."""
    temperatures: Dict[str, TemperatureReading]
    motors: Dict[str, MotorStatus]
    safety: SafetyStatus
    communication_health: float
    system_status: str
    last_update: Optional[str] = None


class MotorControlRequest(BaseModel):
    """Motor control request model."""
    enabled: bool


class HeaterControlRequest(BaseModel):
    """Heater control request model."""
    enabled: bool


@router.get("/status", response_model=HardwareStatusResponse)
async def get_hardware_status():
    """Get complete hardware status."""
    try:
        hw_status = hardware_manager.get_hardware_status()
        
        # Convert temperature readings
        temperatures = {}
        for sensor_name, reading in hw_status.temperatures.items():
            temperatures[sensor_name] = TemperatureReading(
                value=reading.value,
                sensor_name=reading.sensor_name,
                timestamp=reading.timestamp.isoformat(),
                units=reading.units,
                is_valid=reading.is_valid,
                error_message=reading.error_message
            )
        
        # Convert motor statuses
        motors = {}
        for motor_name, motor in hw_status.motors.items():
            motors[motor_name] = MotorStatus(
                name=motor.name,
                state=motor.state.value,
                is_enabled=motor.is_enabled,
                current=motor.current,
                runtime_hours=motor.runtime_hours,
                error_count=motor.error_count
            )
        
        # Convert safety status
        safety = SafetyStatus(
            emergency_stop_active=hw_status.safety.emergency_stop_active,
            cover_sensor_closed=hw_status.safety.cover_sensor_closed,
            temperature_alarms=hw_status.safety.temperature_alarms,
            current_alarms=hw_status.safety.current_alarms,
            last_safety_check=hw_status.safety.last_safety_check.isoformat() if hw_status.safety.last_safety_check else None
        )
        
        return HardwareStatusResponse(
            temperatures=temperatures,
            motors=motors,
            safety=safety,
            communication_health=hw_status.communication_health,
            system_status=hw_status.system_status.value,
            last_update=hw_status.last_update.isoformat() if hw_status.last_update else None
        )
        
    except Exception as e:
        logger.error(f"Failed to get hardware status: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to retrieve hardware status"
        )


@router.get("/temperatures", response_model=Dict[str, TemperatureReading])
async def get_temperatures():
    """Get all temperature readings."""
    try:
        temperatures = await hardware_manager.get_all_temperatures()
        
        result = {}
        for sensor_name, reading in temperatures.items():
            result[sensor_name] = TemperatureReading(
                value=reading.value,
                sensor_name=reading.sensor_name,
                timestamp=reading.timestamp.isoformat(),
                units=reading.units,
                is_valid=reading.is_valid,
                error_message=reading.error_message
            )
        
        return result
        
    except Exception as e:
        logger.error(f"Failed to get temperatures: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to retrieve temperature readings"
        )


@router.get("/temperatures/{sensor_name}", response_model=TemperatureReading)
async def get_temperature(sensor_name: str):
    """Get temperature reading for a specific sensor."""
    try:
        reading = await hardware_manager.get_temperature(sensor_name)
        
        if not reading:
            raise HTTPException(
                status_code=404,
                detail=f"Temperature sensor '{sensor_name}' not found"
            )
        
        return TemperatureReading(
            value=reading.value,
            sensor_name=reading.sensor_name,
            timestamp=reading.timestamp.isoformat(),
            units=reading.units,
            is_valid=reading.is_valid,
            error_message=reading.error_message
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get temperature for {sensor_name}: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Failed to retrieve temperature for sensor '{sensor_name}'"
        )


@router.get("/temperatures/tank/average")
async def get_average_tank_temperature():
    """Get average temperature of tank sensors."""
    try:
        avg_temp = await hardware_manager.get_average_tank_temperature()
        
        if avg_temp is None:
            raise HTTPException(
                status_code=503,
                detail="No valid tank temperature readings available"
            )
        
        return {
            "average_temperature": avg_temp,
            "units": "°C",
            "sensors_used": ["tank_bottom", "tank_wall"],
            "timestamp": hardware_manager.current_status.last_update.isoformat() if hardware_manager.current_status.last_update else None
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get average tank temperature: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to calculate average tank temperature"
        )


@router.get("/motors", response_model=Dict[str, MotorStatus])
async def get_motor_status():
    """Get status of all motors."""
    try:
        hw_status = hardware_manager.get_hardware_status()
        
        motors = {}
        for motor_name, motor in hw_status.motors.items():
            motors[motor_name] = MotorStatus(
                name=motor.name,
                state=motor.state.value,
                is_enabled=motor.is_enabled,
                current=motor.current,
                runtime_hours=motor.runtime_hours,
                error_count=motor.error_count
            )
        
        return motors
        
    except Exception as e:
        logger.error(f"Failed to get motor status: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to retrieve motor status"
        )


@router.post("/motors/{motor_name}/control")
async def control_motor(motor_name: str, request: MotorControlRequest):
    """Enable or disable a specific motor."""
    try:
        success = await hardware_manager.set_motor_state(motor_name, request.enabled)
        
        if not success:
            raise HTTPException(
                status_code=400,
                detail=f"Failed to control motor '{motor_name}'"
            )
        
        action = "enabled" if request.enabled else "disabled"
        return {
            "success": True,
            "message": f"Motor '{motor_name}' {action} successfully",
            "motor_name": motor_name,
            "enabled": request.enabled
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to control motor {motor_name}: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Failed to control motor '{motor_name}'"
        )


@router.post("/motors/disable-all")
async def disable_all_motors():
    """Disable all motors for safety."""
    try:
        success = await hardware_manager.disable_all_motors()
        
        return {
            "success": success,
            "message": "All motors disabled" if success else "Failed to disable all motors"
        }
        
    except Exception as e:
        logger.error(f"Failed to disable all motors: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to disable all motors"
        )


@router.post("/heaters/{heater_name}/control")
async def control_heater(heater_name: str, request: HeaterControlRequest):
    """Enable or disable a specific heater."""
    try:
        success = await hardware_manager.set_heater_state(heater_name, request.enabled)
        
        if not success:
            raise HTTPException(
                status_code=400,
                detail=f"Failed to control heater '{heater_name}'"
            )
        
        action = "enabled" if request.enabled else "disabled"
        return {
            "success": True,
            "message": f"Heater '{heater_name}' {action} successfully",
            "heater_name": heater_name,
            "enabled": request.enabled
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to control heater {heater_name}: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Failed to control heater '{heater_name}'"
        )


@router.post("/heaters/disable-all")
async def disable_all_heaters():
    """Disable all heaters for safety."""
    try:
        success = await hardware_manager.disable_all_heaters()
        
        return {
            "success": success,
            "message": "All heaters disabled" if success else "Failed to disable all heaters"
        }
        
    except Exception as e:
        logger.error(f"Failed to disable all heaters: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to disable all heaters"
        )


@router.post("/emergency-stop")
async def emergency_stop():
    """Execute hardware emergency stop."""
    try:
        success = await hardware_manager.emergency_stop()
        
        return {
            "success": success,
            "message": "Emergency stop executed" if success else "Emergency stop failed"
        }
        
    except Exception as e:
        logger.critical(f"Hardware emergency stop failed: {e}")
        raise HTTPException(
            status_code=500,
            detail="Hardware emergency stop failed"
        )


@router.get("/safety", response_model=SafetyStatus)
async def get_safety_status():
    """Get hardware safety status."""
    try:
        hw_status = hardware_manager.get_hardware_status()
        
        return SafetyStatus(
            emergency_stop_active=hw_status.safety.emergency_stop_active,
            cover_sensor_closed=hw_status.safety.cover_sensor_closed,
            temperature_alarms=hw_status.safety.temperature_alarms,
            current_alarms=hw_status.safety.current_alarms,
            last_safety_check=hw_status.safety.last_safety_check.isoformat() if hw_status.safety.last_safety_check else None
        )
        
    except Exception as e:
        logger.error(f"Failed to get safety status: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to retrieve safety status"
        )


@router.get("/safety/check")
async def check_safety():
    """Perform safety check and return results."""
    try:
        is_safe, issues = await hardware_manager.is_safe_to_operate()
        
        return {
            "is_safe": is_safe,
            "issues": issues,
            "timestamp": hardware_manager.current_status.last_update.isoformat() if hardware_manager.current_status.last_update else None
        }
        
    except Exception as e:
        logger.error(f"Safety check failed: {e}")
        raise HTTPException(
            status_code=500,
            detail="Safety check failed"
        )


@router.get("/communication/statistics")
async def get_communication_statistics():
    """Get Modbus communication statistics."""
    try:
        stats = hardware_manager.get_communication_statistics()
        return stats
        
    except Exception as e:
        logger.error(f"Failed to get communication statistics: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to retrieve communication statistics"
        )