//! Contract for the hosted `image_generation` tool.
//!
//! The tool is a hosted/provider capability, not a local Rust image renderer.
//! Runtimes that support it should persist generated bytes under a
//! session-scoped generated-media root, then return stable file paths in tool
//! output so final answers can reference concrete artifacts.

use serde::{Deserialize, Serialize};
use serde_json::json;

use super::{ImagePermission, ImageToolSpec};

/// Stable model-facing tool name.
pub const IMAGE_GENERATION_TOOL_NAME: &str = "image_generation";

/// Generated image file format requested from the hosted provider.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ImageGenerationOutputFormat {
    Png,
    Webp,
    Jpeg,
}

impl ImageGenerationOutputFormat {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Png => "png",
            Self::Webp => "webp",
            Self::Jpeg => "jpeg",
        }
    }
}

/// Build the hosted `image_generation` model-facing contract.
pub fn image_generation_spec(output_format: ImageGenerationOutputFormat) -> ImageToolSpec {
    ImageToolSpec {
        name: IMAGE_GENERATION_TOOL_NAME.to_string(),
        description: "Generate or edit raster images from a prompt and store each result as a local artifact path for the user.".to_string(),
        parameters: json!({
            "type": "object",
            "properties": {
                "prompt": {
                    "type": "string",
                    "description": "Detailed visual prompt or edit instruction for the hosted image model."
                },
                "output_path": {
                    "type": "string",
                    "description": "Optional workspace-relative or approved absolute output path. When omitted, the runtime chooses a generated-media path."
                },
                "size": {
                    "type": "string",
                    "description": "Optional output size such as 1024x1024, 1536x1024, or provider default."
                },
                "input_image_path": {
                    "type": "string",
                    "description": "Optional local image path to edit. The runtime must validate local-file access before attaching it."
                },
                "output_format": {
                    "type": "string",
                    "enum": ["png", "webp", "jpeg"],
                    "default": output_format.as_str(),
                    "description": "Requested persisted file format."
                }
            },
            "required": ["prompt"]
        }),
        permission: ImagePermission::Write,
        model_visible_image_output: false,
        writes_files: true,
    }
}

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

    #[test]
    fn image_generation_schema_declares_output_path_and_format() {
        let spec = image_generation_spec(ImageGenerationOutputFormat::Webp);

        assert_eq!(spec.name, "image_generation");
        assert!(spec.description.contains("Generate or edit raster images"));
        assert_eq!(spec.permission, ImagePermission::Write);
        assert!(!spec.model_visible_image_output);
        assert!(spec.writes_files);
        assert_eq!(spec.parameters["required"], serde_json::json!(["prompt"]));
        assert!(spec.parameters["properties"].get("output_path").is_some());
        assert_eq!(
            spec.parameters["properties"]["output_format"]["default"],
            "webp"
        );
    }

    #[test]
    fn output_format_serializes_as_snake_case() {
        assert_eq!(ImageGenerationOutputFormat::Png.as_str(), "png");
        assert_eq!(ImageGenerationOutputFormat::Webp.as_str(), "webp");
        assert_eq!(ImageGenerationOutputFormat::Jpeg.as_str(), "jpeg");

        assert_eq!(
            serde_json::to_value(ImageGenerationOutputFormat::Webp).unwrap(),
            serde_json::json!("webp")
        );
        assert_eq!(
            serde_json::from_value::<ImageGenerationOutputFormat>(serde_json::json!("jpeg"))
                .unwrap(),
            ImageGenerationOutputFormat::Jpeg
        );
    }

    #[test]
    fn image_generation_schema_keeps_edit_and_size_inputs_optional() {
        let spec = image_generation_spec(ImageGenerationOutputFormat::Png);
        let properties = spec.parameters["properties"].as_object().unwrap();

        assert_eq!(
            properties.keys().cloned().collect::<Vec<_>>(),
            vec![
                "input_image_path".to_string(),
                "output_format".to_string(),
                "output_path".to_string(),
                "prompt".to_string(),
                "size".to_string()
            ]
        );
        assert_eq!(
            properties["output_format"]["enum"],
            serde_json::json!(["png", "webp", "jpeg"])
        );
    }
}
