//! Authentication domain logic — OPAQUE registration and login.
//!
//! This module contains the pure business logic for OPAQUE auth,
//! extracted from `node_service/auth_ops.rs`. It operates on domain
//! types and the `Store` trait, with no dependency on Cap'n Proto or Protobuf.

use std::sync::Arc;

use dashmap::DashMap;
use opaque_ke::ServerSetup;
use quicproquo_core::opaque_auth::OpaqueSuite;

use crate::auth::{AuthConfig, PendingLogin, SessionInfo};
use crate::storage::{Store, StorageError};

use super::types::*;

/// Shared state needed by auth operations.
pub struct AuthService {
    pub store: Arc<dyn Store>,
    pub opaque_setup: Arc<ServerSetup<OpaqueSuite>>,
    pub pending_logins: Arc<DashMap<String, PendingLogin>>,
    pub sessions: Arc<DashMap<Vec<u8>, SessionInfo>>,
    pub auth_cfg: Arc<AuthConfig>,
}

impl AuthService {
    /// Validate a session token and return the caller's auth context.
    pub fn validate_session(&self, token: &[u8]) -> Option<CallerAuth> {
        let info = self.sessions.get(token)?;
        if info.expires_at <= crate::auth::current_timestamp() {
            self.sessions.remove(token);
            return None;
        }
        Some(CallerAuth {
            identity_key: info.identity_key.clone(),
            token: token.to_vec(),
            device_id: None,
        })
    }

    /// Start OPAQUE registration.
    pub fn register_start(&self, req: RegisterStartReq) -> Result<RegisterStartResp, StorageError> {
        use opaque_ke::ServerRegistration;

        let result = ServerRegistration::<OpaqueSuite>::start(
            &self.opaque_setup,
            opaque_ke::RegistrationRequest::deserialize(&req.request_bytes)
                .map_err(|e| StorageError::Io(format!("bad registration request: {e}")))?,
            req.username.as_bytes(),
        )
        .map_err(|e| StorageError::Io(format!("OPAQUE register start: {e}")))?;

        let response_bytes = result.message.serialize().to_vec();
        Ok(RegisterStartResp { response_bytes })
    }

    /// Finish OPAQUE registration — persist user record and identity key.
    pub fn register_finish(&self, req: RegisterFinishReq) -> Result<RegisterFinishResp, StorageError> {
        let upload = opaque_ke::RegistrationUpload::<OpaqueSuite>::deserialize(&req.upload_bytes)
            .map_err(|e| StorageError::Io(format!("bad registration upload: {e}")))?;

        let record = opaque_ke::ServerRegistration::<OpaqueSuite>::finish(upload);
        let serialized = record.serialize().to_vec();

        self.store.store_user_record(&req.username, serialized)?;
        self.store
            .store_user_identity_key(&req.username, req.identity_key)?;

        Ok(RegisterFinishResp { success: true })
    }
}
