use llm_kit_provider::shared::provider_options::SharedProviderOptions;
use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Tool call content part of a prompt.
///
/// It contains a tool call (usually generated by the AI model).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolCallPart {
    /// ID of the tool call. This ID is used to match the tool call with the tool result.
    #[serde(rename = "toolCallId")]
    pub tool_call_id: String,

    /// Name of the tool that is being called.
    #[serde(rename = "toolName")]
    pub tool_name: String,

    /// Arguments of the tool call.
    ///
    /// This is a JSON-serializable object that matches the tool's input schema.
    /// Use `Value` to represent any JSON-serializable data.
    pub input: Value,

    /// Additional provider-specific metadata.
    #[serde(rename = "providerOptions", skip_serializing_if = "Option::is_none")]
    pub provider_options: Option<SharedProviderOptions>,

    /// Whether the tool call was executed by the provider.
    #[serde(rename = "providerExecuted", skip_serializing_if = "Option::is_none")]
    pub provider_executed: Option<bool>,
}

impl ToolCallPart {
    /// Creates a new tool call part.
    pub fn new(
        tool_call_id: impl Into<String>,
        tool_name: impl Into<String>,
        input: Value,
    ) -> Self {
        Self {
            tool_call_id: tool_call_id.into(),
            tool_name: tool_name.into(),
            input,
            provider_options: None,
            provider_executed: None,
        }
    }

    /// Sets the provider options.
    pub fn with_provider_options(mut self, options: SharedProviderOptions) -> Self {
        self.provider_options = Some(options);
        self
    }

    /// Sets whether the tool call was executed by the provider.
    pub fn with_provider_executed(mut self, executed: bool) -> Self {
        self.provider_executed = Some(executed);
        self
    }
}

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

    #[test]
    fn test_tool_call_part_new() {
        let input = json!({"city": "San Francisco"});
        let part = ToolCallPart::new("call_123", "get_weather", input.clone());

        assert_eq!(part.tool_call_id, "call_123");
        assert_eq!(part.tool_name, "get_weather");
        assert_eq!(part.input, input);
        assert!(part.provider_options.is_none());
        assert!(part.provider_executed.is_none());
    }

    #[test]
    fn test_tool_call_part_with_provider_executed() {
        let input = json!({});
        let part = ToolCallPart::new("call_456", "tool", input).with_provider_executed(true);

        assert_eq!(part.provider_executed, Some(true));
    }
}
