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 super::NodeServiceImpl;

impl NodeServiceImpl {
    pub fn handle_delete_account(
        &mut self,
        params: node_service::DeleteAccountParams,
        mut results: node_service::DeleteAccountResults,
    ) -> Promise<(), capnp::Error> {
        let p = match params.get() {
            Ok(p) => p,
            Err(e) => return Promise::err(coded_error(E020_BAD_PARAMS, e)),
        };

        // Validate auth and require an identity-bound session.
        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_key = match require_identity(&auth_ctx) {
            Ok(ik) => ik.to_vec(),
            Err(e) => return Promise::err(e),
        };

        let identity_prefix = crate::auth::fmt_hex(&identity_key[..8.min(identity_key.len())]);

        // Delete account data from the store.
        if let Err(e) = self.store.delete_account(&identity_key) {
            tracing::error!(identity = %identity_prefix, error = %e, "account deletion failed");
            return Promise::err(coded_error(
                E028_ACCOUNT_DELETION_FAILED,
                format!("account deletion failed: {e}"),
            ));
        }

        // Invalidate all sessions for this identity.
        let tokens_to_remove: Vec<Vec<u8>> = self
            .sessions
            .iter()
            .filter(|entry| entry.value().identity_key == identity_key)
            .map(|entry| entry.key().clone())
            .collect();

        for token in &tokens_to_remove {
            self.sessions.remove(token);
        }

        tracing::info!(
            identity = %identity_prefix,
            sessions_invalidated = tokens_to_remove.len(),
            "audit: account deleted"
        );

        results.get().set_success(true);
        Promise::ok(())
    }
}
