use crate::devices::device::{DeviceGeneralInfo, DeviceId};
use crate::energy::energy_actor;
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult;
use actix_web::{HttpResponse, web};

/// Get the list of pending (not accepted yet) devices
pub async fn list_pending(actor: WebEnergyActor) -> HttpResult {
    let list = actor
        .send(energy_actor::GetDeviceLists)
        .await?
        .into_iter()
        .filter(|d| !d.validated)
        .collect::<Vec<_>>();

    Ok(HttpResponse::Ok().json(list))
}

/// Get the list of validated (not accepted yet) devices
pub async fn list_validated(actor: WebEnergyActor) -> HttpResult {
    let list = actor
        .send(energy_actor::GetDeviceLists)
        .await?
        .into_iter()
        .filter(|d| d.validated)
        .collect::<Vec<_>>();

    Ok(HttpResponse::Ok().json(list))
}

/// Get the state of devices
pub async fn devices_state(actor: WebEnergyActor) -> HttpResult {
    let states = actor.send(energy_actor::GetDevicesState).await?;

    Ok(HttpResponse::Ok().json(states))
}

#[derive(serde::Deserialize)]
pub struct DeviceInPath {
    id: DeviceId,
}

/// Get a single device information
pub async fn get_single(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> HttpResult {
    let Some(dev) = actor
        .send(energy_actor::GetSingleDevice(id.id.clone()))
        .await?
    else {
        return Ok(HttpResponse::NotFound().json("Requested device was not found!"));
    };

    Ok(HttpResponse::Ok().json(dev))
}

/// Get a single device state
pub async fn state_single(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> HttpResult {
    let states = actor.send(energy_actor::GetDevicesState).await?;

    let Some(state) = states.into_iter().find(|s| s.id == id.id) else {
        return Ok(HttpResponse::NotFound().body("Requested device not found!"));
    };

    Ok(HttpResponse::Ok().json(state))
}

/// Validate a device
pub async fn validate_device(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> HttpResult {
    actor
        .send(energy_actor::ValidateDevice(id.id.clone()))
        .await??;

    Ok(HttpResponse::Accepted().finish())
}

/// Update a device information
pub async fn update_device(
    actor: WebEnergyActor,
    id: web::Path<DeviceInPath>,
    update: web::Json<DeviceGeneralInfo>,
) -> HttpResult {
    if let Some(e) = update.error() {
        return Ok(HttpResponse::BadRequest().json(e));
    }

    actor
        .send(energy_actor::UpdateDeviceGeneralInfo(
            id.id.clone(),
            update.0.clone(),
        ))
        .await??;

    Ok(HttpResponse::Accepted().finish())
}

/// Delete a device
pub async fn delete_device(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> HttpResult {
    actor
        .send(energy_actor::DeleteDevice(id.id.clone()))
        .await??;

    Ok(HttpResponse::Accepted().finish())
}