//! OpenAI Responses API types and conversion.
//!
//! This module handles the newer Responses API format used by Codex CLI.

use serde::{Deserialize, Serialize};

/// Request to create a response (POST /v1/responses)
#[derive(Debug, Clone, Deserialize)]
pub struct ResponsesRequest {
    /// Model ID to use
    #[serde(default)]
    pub model: Option<String>,

    /// Input text or array of input items
    #[serde(default)]
    pub input: Option<ResponseInput>,

    /// System instructions
    #[serde(default)]
    pub instructions: Option<String>,

    /// Whether to stream the response
    #[serde(default)]
    pub stream: bool,

    /// Temperature for sampling
    #[serde(default)]
    pub temperature: Option<f32>,

    /// Top-p sampling
    #[serde(default)]
    pub top_p: Option<f32>,

    /// Maximum output tokens
    #[serde(default)]
    pub max_output_tokens: Option<u32>,

    /// Tools available to the model
    #[serde(default)]
    pub tools: Option<Vec<ResponseTool>>,
}

/// Input can be a string or array of input items
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum ResponseInput {
    Text(String),
    Items(Vec<ResponseInputItem>),
}

/// An input item in the conversation
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type")]
pub enum ResponseInputItem {
    #[serde(rename = "message")]
    Message {
        role: String,
        content: ResponseInputContent,
    },
    #[serde(other)]
    Other,
}

/// Content of an input message
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum ResponseInputContent {
    Text(String),
    Parts(Vec<ResponseInputPart>),
}

/// A part of input content
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type")]
pub enum ResponseInputPart {
    #[serde(rename = "input_text")]
    InputText { text: String },
    #[serde(rename = "output_text")]
    OutputText { text: String },
    #[serde(other)]
    Other,
}

/// Tool definition
#[derive(Debug, Clone, Deserialize)]
pub struct ResponseTool {
    #[serde(rename = "type")]
    pub tool_type: String,
    #[serde(default)]
    pub name: Option<String>,
    #[serde(default)]
    pub description: Option<String>,
    #[serde(default)]
    pub parameters: Option<serde_json::Value>,
}

// ============================================================================
// Response types
// ============================================================================

/// Response from the Responses API
#[derive(Debug, Clone, Serialize)]
pub struct ResponsesResponse {
    /// Unique identifier for this Response
    pub id: String,

    /// Object type, always "response"
    pub object: &'static str,

    /// Unix timestamp of creation
    pub created_at: f64,

    /// Model ID used
    pub model: String,

    /// Output items generated by the model
    pub output: Vec<ResponseOutputItem>,

    /// Whether parallel tool calls are enabled
    pub parallel_tool_calls: bool,

    /// Tool choice setting
    pub tool_choice: &'static str,

    /// Tools available
    pub tools: Vec<serde_json::Value>,

    /// Temperature used
    #[serde(skip_serializing_if = "Option::is_none")]
    pub temperature: Option<f32>,

    /// Top-p used
    #[serde(skip_serializing_if = "Option::is_none")]
    pub top_p: Option<f32>,

    /// Max output tokens
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_output_tokens: Option<u32>,

    /// Usage statistics
    #[serde(skip_serializing_if = "Option::is_none")]
    pub usage: Option<ResponseUsage>,

    /// Response status
    pub status: &'static str,
}

/// An output item in the response
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type")]
pub enum ResponseOutputItem {
    #[serde(rename = "message")]
    Message {
        id: String,
        role: &'static str,
        status: &'static str,
        content: Vec<ResponseOutputContent>,
    },
    #[serde(rename = "reasoning")]
    Reasoning {
        id: String,
        status: &'static str,
        summary: Option<Vec<ResponseOutputContent>>,
    },
    #[serde(rename = "function_call")]
    FunctionCall {
        id: String,
        call_id: String,
        name: String,
        arguments: String,
        status: &'static str,
    },
}

/// Content of an output message
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type")]
pub enum ResponseOutputContent {
    #[serde(rename = "output_text")]
    OutputText {
        text: String,
        #[serde(skip_serializing_if = "Vec::is_empty")]
        annotations: Vec<serde_json::Value>,
    },
}

/// Usage statistics
#[derive(Debug, Clone, Serialize)]
pub struct ResponseUsage {
    pub input_tokens: u32,
    pub output_tokens: u32,
    pub total_tokens: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub input_tokens_details: Option<InputTokensDetails>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub output_tokens_details: Option<OutputTokensDetails>,
}

#[derive(Debug, Clone, Serialize)]
pub struct InputTokensDetails {
    pub cached_tokens: u32,
}

#[derive(Debug, Clone, Serialize)]
pub struct OutputTokensDetails {
    pub reasoning_tokens: u32,
}

// ============================================================================
// Streaming types
// ============================================================================

/// Streaming event for Responses API
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type")]
pub enum ResponseStreamEvent {
    #[serde(rename = "response.created")]
    ResponseCreated { response: Box<ResponsesResponse> },

    #[serde(rename = "response.output_item.added")]
    OutputItemAdded {
        output_index: usize,
        item: ResponseOutputItem,
    },

    #[serde(rename = "response.output_item.done")]
    OutputItemDone {
        output_index: usize,
        item: ResponseOutputItem,
    },

    #[serde(rename = "response.content_part.added")]
    ContentPartAdded {
        output_index: usize,
        content_index: usize,
        part: ResponseOutputContent,
    },

    #[serde(rename = "response.content_part.done")]
    ContentPartDone {
        output_index: usize,
        content_index: usize,
        part: ResponseOutputContent,
    },

    #[serde(rename = "response.output_text.delta")]
    OutputTextDelta {
        output_index: usize,
        content_index: usize,
        delta: String,
    },

    #[serde(rename = "response.output_text.done")]
    OutputTextDone {
        output_index: usize,
        content_index: usize,
        text: String,
    },

    #[serde(rename = "response.completed")]
    ResponseCompleted { response: Box<ResponsesResponse> },
}
