//! Workflow execution result types.

use std::collections::HashMap;

use car_ir::ProposalResult;
use car_multi::AgentOutput;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Overall workflow execution result.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowResult {
    pub workflow_id: String,
    pub workflow_name: String,
    pub status: WorkflowStatus,
    /// Results for each stage that executed (in execution order).
    pub stages: Vec<StageResult>,
    /// Compensation records (in compensation order, reverse of execution).
    pub compensations: Vec<CompensationResult>,
    pub duration_ms: f64,
    pub timestamp: DateTime<Utc>,
    /// Final workflow state snapshot.
    #[serde(default)]
    pub final_state: HashMap<String, Value>,
}

impl WorkflowResult {
    pub fn succeeded(&self) -> bool {
        self.status == WorkflowStatus::Completed
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WorkflowStatus {
    /// All stages completed successfully.
    Completed,
    /// A stage failed and no compensation was attempted.
    Failed,
    /// A stage failed and all compensations succeeded.
    Compensated,
    /// A stage failed and some compensations also failed.
    PartiallyCompensated,
}

/// Result of a single stage execution.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StageResult {
    pub stage_id: String,
    pub stage_name: String,
    pub status: StageStatus,
    pub output: StageOutput,
    pub duration_ms: f64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StageStatus {
    Succeeded,
    Failed,
    Skipped,
    Compensated,
}

/// The typed output of a stage, depending on its step type.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum StageOutput {
    Pattern {
        outputs: Vec<AgentOutput>,
        final_answer: String,
    },
    Proposal {
        result: ProposalResult,
    },
    SubWorkflow {
        result: Box<WorkflowResult>,
    },
    Empty,
}

/// Record of a compensation attempt.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompensationResult {
    pub for_stage_id: String,
    pub status: StageStatus,
    pub duration_ms: f64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
}
