use tonic::{metadata::MetadataMap, Status};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TenantContext {
    pub org_id: String,
    pub project_id: String,
}

fn metadata_value(metadata: &MetadataMap, key: &str) -> Option<String> {
    metadata
        .get(key)
        .and_then(|value| value.to_str().ok())
        .map(|value| value.trim().to_string())
        .filter(|value| !value.is_empty())
}

fn org_from_metadata(metadata: &MetadataMap) -> Option<String> {
    metadata_value(metadata, "org-id")
        .or_else(|| metadata_value(metadata, "x-org-id"))
        .or_else(|| metadata_value(metadata, "org_id"))
}

fn project_from_metadata(metadata: &MetadataMap) -> Option<String> {
    metadata_value(metadata, "project-id")
        .or_else(|| metadata_value(metadata, "x-project-id"))
        .or_else(|| metadata_value(metadata, "project_id"))
}

pub fn resolve_org(
    metadata: &MetadataMap,
    org_id: Option<String>,
) -> Result<String, Status> {
    org_id
        .filter(|value| !value.is_empty())
        .or_else(|| org_from_metadata(metadata))
        .ok_or_else(|| Status::invalid_argument("org_id is required"))
}

pub fn resolve_org_project_optional(
    metadata: &MetadataMap,
    org_id: Option<String>,
    project_id: Option<String>,
) -> Result<(String, Option<String>), Status> {
    let org_id = resolve_org(metadata, org_id)?;
    let project_id = project_id
        .filter(|value| !value.is_empty())
        .or_else(|| project_from_metadata(metadata));
    Ok((org_id, project_id))
}

pub fn resolve_tenant(
    metadata: &MetadataMap,
    org_id: Option<String>,
    project_id: Option<String>,
) -> Result<TenantContext, Status> {
    let (org_id, project_id) = resolve_org_project_optional(metadata, org_id, project_id)?;
    let project_id = project_id.ok_or_else(|| Status::invalid_argument("project_id is required"))?;
    Ok(TenantContext { org_id, project_id })
}
