use serde::Serialize;

#[derive(Debug, Serialize)]
pub struct RobotMeta {
    pub elapsed_ms: u64,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub gitlab_base_url: Option<String>,
}

impl RobotMeta {
    /// Standard meta with timing only.
    pub fn new(elapsed_ms: u64) -> Self {
        Self {
            elapsed_ms,
            gitlab_base_url: None,
        }
    }

    /// Meta with GitLab base URL for URL construction by consumers.
    pub fn with_base_url(elapsed_ms: u64, base_url: &str) -> Self {
        Self {
            elapsed_ms,
            gitlab_base_url: Some(base_url.trim_end_matches('/').to_string()),
        }
    }
}

/// Filter JSON object fields in-place for `--fields` support.
/// Retains only the specified field names on each item in the list array.
pub fn filter_fields(value: &mut serde_json::Value, list_key: &str, fields: &[String]) {
    if fields.is_empty() {
        return;
    }
    if let Some(items) = value
        .get_mut("data")
        .and_then(|d| d.get_mut(list_key))
        .and_then(|v| v.as_array_mut())
    {
        for item in items {
            if let Some(obj) = item.as_object_mut() {
                obj.retain(|k, _| fields.iter().any(|f| f == k));
            }
        }
    }
}

/// Expand the `minimal` preset into concrete field names.
pub fn expand_fields_preset(fields: &[String], entity: &str) -> Vec<String> {
    if fields.len() == 1 && fields[0] == "minimal" {
        match entity {
            "issues" => ["iid", "title", "state", "updated_at_iso"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "mrs" => ["iid", "title", "state", "updated_at_iso"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "search" => [
                "document_id",
                "title",
                "source_type",
                "source_entity_iid",
                "score",
            ]
            .iter()
            .map(|s| (*s).to_string())
            .collect(),
            "timeline" => ["timestamp", "type", "entity_iid", "detail"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "who_expert" => ["username", "score"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "who_workload" => ["iid", "title", "state"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "who_active" => ["entity_type", "iid", "title", "participants"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "who_overlap" => ["username", "touch_count"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "who_reviews" => ["name", "count", "percentage"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "notes" => ["id", "author_username", "body", "created_at_iso"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            "me_items" => [
                "iid",
                "title",
                "attention_state",
                "attention_reason",
                "updated_at_iso",
            ]
            .iter()
            .map(|s| (*s).to_string())
            .collect(),
            "me_mentions" => [
                "entity_type",
                "iid",
                "title",
                "state",
                "attention_state",
                "attention_reason",
                "updated_at_iso",
            ]
            .iter()
            .map(|s| (*s).to_string())
            .collect(),
            "me_activity" => ["timestamp_iso", "event_type", "entity_iid", "actor"]
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            _ => fields.to_vec(),
        }
    } else {
        fields.to_vec()
    }
}

/// Strip `response_schema` from every command entry for `--brief` mode.
pub fn strip_schemas(commands: &mut serde_json::Value) {
    if let Some(map) = commands.as_object_mut() {
        for (_cmd_name, cmd) in map.iter_mut() {
            if let Some(obj) = cmd.as_object_mut() {
                obj.remove("response_schema");
                obj.remove("example_output");
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_expand_fields_preset_notes() {
        let fields = vec!["minimal".to_string()];
        let expanded = expand_fields_preset(&fields, "notes");
        assert_eq!(
            expanded,
            ["id", "author_username", "body", "created_at_iso"]
        );
    }

    #[test]
    fn test_expand_fields_preset_passthrough() {
        let fields = vec!["id".to_string(), "body".to_string()];
        let expanded = expand_fields_preset(&fields, "notes");
        assert_eq!(expanded, ["id", "body"]);
    }

    #[test]
    fn meta_new_omits_base_url() {
        let meta = RobotMeta::new(42);
        let json = serde_json::to_value(&meta).unwrap();
        assert_eq!(json["elapsed_ms"], 42);
        assert!(json.get("gitlab_base_url").is_none());
    }

    #[test]
    fn meta_with_base_url_includes_it() {
        let meta = RobotMeta::with_base_url(99, "https://gitlab.example.com");
        let json = serde_json::to_value(&meta).unwrap();
        assert_eq!(json["elapsed_ms"], 99);
        assert_eq!(json["gitlab_base_url"], "https://gitlab.example.com");
    }

    #[test]
    fn meta_with_base_url_strips_trailing_slash() {
        let meta = RobotMeta::with_base_url(0, "https://gitlab.example.com/");
        let json = serde_json::to_value(&meta).unwrap();
        assert_eq!(json["gitlab_base_url"], "https://gitlab.example.com");
    }
}
