//! Device handlers — register, list, revoke devices.

use std::sync::Arc;

use bytes::Bytes;
use prost::Message;
use quicproquo_proto::qpq::v1;
use quicproquo_rpc::method::{HandlerResult, RequestContext};

use crate::domain::devices::DeviceService;
use crate::domain::types::{RegisterDeviceReq, RevokeDeviceReq};

use super::{domain_err, require_auth, ServerState};

pub async fn handle_register_device(
    state: Arc<ServerState>,
    ctx: RequestContext,
) -> HandlerResult {
    let identity_key = match require_auth(&state, &ctx) {
        Ok(ik) => ik,
        Err(e) => return e,
    };

    let req = match v1::RegisterDeviceRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = DeviceService {
        store: Arc::clone(&state.store),
    };

    let domain_req = RegisterDeviceReq {
        device_id: req.device_id,
        device_name: req.device_name,
    };

    match svc.register_device(domain_req, &identity_key) {
        Ok(resp) => {
            let proto = v1::RegisterDeviceResponse {
                success: resp.success,
            };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}

pub async fn handle_list_devices(state: Arc<ServerState>, ctx: RequestContext) -> HandlerResult {
    let identity_key = match require_auth(&state, &ctx) {
        Ok(ik) => ik,
        Err(e) => return e,
    };

    // ListDevicesRequest is empty but we still decode for protocol correctness.
    let _req = match v1::ListDevicesRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = DeviceService {
        store: Arc::clone(&state.store),
    };

    match svc.list_devices(&identity_key) {
        Ok(resp) => {
            let proto = v1::ListDevicesResponse {
                devices: resp
                    .devices
                    .into_iter()
                    .map(|d| v1::Device {
                        device_id: d.device_id,
                        device_name: d.device_name,
                        registered_at: d.registered_at,
                    })
                    .collect(),
            };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}

pub async fn handle_revoke_device(state: Arc<ServerState>, ctx: RequestContext) -> HandlerResult {
    let identity_key = match require_auth(&state, &ctx) {
        Ok(ik) => ik,
        Err(e) => return e,
    };

    let req = match v1::RevokeDeviceRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = DeviceService {
        store: Arc::clone(&state.store),
    };

    let domain_req = RevokeDeviceReq {
        device_id: req.device_id,
    };

    match svc.revoke_device(domain_req, &identity_key) {
        Ok(resp) => {
            let proto = v1::RevokeDeviceResponse {
                success: resp.success,
            };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}
