use actix_web::HttpRequest;
use uuid::Uuid;

use crate::api::headers::x_company_id::get_x_company_id;
use crate::api::headers::x_organization_id::get_x_organization_id;
use crate::api::headers::x_user_id::get_x_user_id;

/// Extracts auditing identity information from Athena requests.
pub struct InsertIdentity {
    pub trace_id: String,
    pub apikey: Option<String>,
    pub user_id: Option<String>,
    pub company_id: Option<String>,
    pub organization_id: Option<String>,
}

impl InsertIdentity {
    pub fn from_request(req: &HttpRequest) -> Self {
        let trace_id: String = Uuid::new_v4().to_string();
        let apikey: Option<String> = req
            .headers()
            .get("x-athena-key")
            .and_then(|value| value.to_str().ok())
            .map(|s| s.to_string())
            .filter(|key| key == &std::env::var("SUITSBOOKS_API_ADMIN_KEY").unwrap_or_default());

        Self {
            trace_id,
            apikey,
            user_id: get_x_user_id(req),
            company_id: get_x_company_id(req),
            organization_id: get_x_organization_id(req),
        }
    }

    pub fn resolved_user_id(&self) -> Option<&String> {
        self.user_id.as_ref().or(self.apikey.as_ref())
    }

    pub fn resolved_company_id(&self) -> Option<&String> {
        self.company_id.as_ref().or(self.apikey.as_ref())
    }

    pub fn resolved_organization_id(&self) -> Option<&String> {
        self.organization_id.as_ref().or(self.apikey.as_ref())
    }

    pub fn audit_user_id(&self) -> String {
        self.resolved_user_id()
            .cloned()
            .unwrap_or_else(|| "unknown-user".to_string())
    }

    pub fn audit_company_id(&self) -> String {
        self.resolved_company_id()
            .cloned()
            .unwrap_or_else(|| "unknown-company".to_string())
    }

    pub fn audit_organization_id(&self) -> String {
        self.resolved_organization_id()
            .cloned()
            .unwrap_or_else(|| "unknown-organization".to_string())
    }
}
