//! Key management handlers — KeyPackage and hybrid key operations.

use std::sync::Arc;

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

use crate::domain::keys::KeyService;
use crate::domain::types::{
    CallerAuth, FetchHybridKeyReq, FetchHybridKeysReq, FetchKeyPackageReq, UploadHybridKeyReq,
    UploadKeyPackageReq,
};

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

fn caller_auth(identity_key: Vec<u8>) -> CallerAuth {
    CallerAuth {
        identity_key,
        token: Vec::new(),
        device_id: None,
    }
}

pub async fn handle_upload_key_package(
    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::UploadKeyPackageRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = KeyService {
        store: Arc::clone(&state.store),
    };
    let auth = caller_auth(identity_key);

    let domain_req = UploadKeyPackageReq {
        identity_key: req.identity_key,
        package: req.package,
    };

    match svc.upload_key_package(domain_req, &auth) {
        Ok(resp) => {
            let proto = v1::UploadKeyPackageResponse {
                fingerprint: resp.fingerprint,
            };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}

pub async fn handle_fetch_key_package(
    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::FetchKeyPackageRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = KeyService {
        store: Arc::clone(&state.store),
    };
    let auth = caller_auth(identity_key);

    let domain_req = FetchKeyPackageReq {
        identity_key: req.identity_key,
    };

    match svc.fetch_key_package(domain_req, &auth) {
        Ok(resp) => {
            let proto = v1::FetchKeyPackageResponse {
                package: resp.package,
            };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}

pub async fn handle_upload_hybrid_key(
    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::UploadHybridKeyRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = KeyService {
        store: Arc::clone(&state.store),
    };
    let auth = caller_auth(identity_key);

    let domain_req = UploadHybridKeyReq {
        identity_key: req.identity_key,
        hybrid_public_key: req.hybrid_public_key,
    };

    match svc.upload_hybrid_key(domain_req, &auth) {
        Ok(()) => {
            let proto = v1::UploadHybridKeyResponse {};
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}

pub async fn handle_fetch_hybrid_key(
    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::FetchHybridKeyRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = KeyService {
        store: Arc::clone(&state.store),
    };
    let auth = caller_auth(identity_key);

    let domain_req = FetchHybridKeyReq {
        identity_key: req.identity_key,
    };

    match svc.fetch_hybrid_key(domain_req, &auth) {
        Ok(resp) => {
            let proto = v1::FetchHybridKeyResponse {
                hybrid_public_key: resp.hybrid_public_key,
            };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}

pub async fn handle_fetch_hybrid_keys(
    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::FetchHybridKeysRequest::decode(ctx.payload) {
        Ok(r) => r,
        Err(e) => {
            return HandlerResult::err(
                quicproquo_rpc::error::RpcStatus::BadRequest,
                &format!("decode: {e}"),
            )
        }
    };

    let svc = KeyService {
        store: Arc::clone(&state.store),
    };
    let auth = caller_auth(identity_key);

    let domain_req = FetchHybridKeysReq {
        identity_keys: req.identity_keys,
    };

    match svc.fetch_hybrid_keys(domain_req, &auth) {
        Ok(resp) => {
            let proto = v1::FetchHybridKeysResponse { keys: resp.keys };
            HandlerResult::ok(Bytes::from(proto.encode_to_vec()))
        }
        Err(e) => domain_err(e),
    }
}
