//! createChannel RPC: create or look up a 1:1 DM channel.

use capnp::capability::Promise;
use quicproquo_proto::node_capnp::node_service;

use crate::auth::{coded_error, require_identity, validate_auth_context};
use crate::error_codes::*;
use crate::storage::StorageError;

use crate::hooks::ChannelEvent;

use super::NodeServiceImpl;

fn storage_err(err: StorageError) -> capnp::Error {
    coded_error(E009_STORAGE_ERROR, err)
}

impl NodeServiceImpl {
    pub fn handle_create_channel(
        &mut self,
        params: node_service::CreateChannelParams,
        mut results: node_service::CreateChannelResults,
    ) -> Promise<(), capnp::Error> {
        let p = match params.get() {
            Ok(p) => p,
            Err(e) => return Promise::err(coded_error(E020_BAD_PARAMS, e)),
        };
        let peer_key = match p.get_peer_key() {
            Ok(v) => v.to_vec(),
            Err(e) => return Promise::err(coded_error(E020_BAD_PARAMS, e)),
        };
        let auth_ctx = match validate_auth_context(&self.auth_cfg, &self.sessions, p.get_auth()) {
            Ok(ctx) => ctx,
            Err(e) => return Promise::err(e),
        };

        let identity = match require_identity(&auth_ctx) {
            Ok(id) => id,
            Err(e) => return Promise::err(e),
        };

        if peer_key.len() != 32 {
            return Promise::err(coded_error(
                E004_IDENTITY_KEY_LENGTH,
                format!("peerKey must be exactly 32 bytes, got {}", peer_key.len()),
            ));
        }

        if identity == peer_key {
            return Promise::err(coded_error(
                E020_BAD_PARAMS,
                "peerKey must not equal caller identity",
            ));
        }

        let (channel_id, was_new) = match self.store.create_channel(identity, &peer_key) {
            Ok(pair) => pair,
            Err(e) => return Promise::err(storage_err(e)),
        };

        // Hook: on_channel_created — fires after channel is created or looked up.
        self.hooks.on_channel_created(&ChannelEvent {
            channel_id: channel_id.clone(),
            initiator_key: identity.to_vec(),
            peer_key: peer_key.clone(),
            was_new,
        });

        let mut r = results.get();
        r.set_channel_id(&channel_id);
        r.set_was_new(was_new);
        Promise::ok(())
    }
}
