//! Workflow step execution models and state.

use crate::id::*;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;

use utoipa::ToSchema;

/// The execution status of a single workflow step.
#[derive(
    Debug, Serialize, Deserialize, Clone, sqlx::Type, PartialEq, Eq, ToSchema, schemars::JsonSchema,
)]
#[sqlx(type_name = "step_status", rename_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum StepStatus {
    /// The step is waiting for dependencies or an available runner.
    Pending,
    /// The runner is unpacking the Stormchaser File System (SFS).
    UnpackingSfs,
    /// The step is actively executing on a runner.
    Running,
    /// The runner is packing and uploading the modified SFS.
    PackingSfs,
    /// The step completed successfully.
    Succeeded,
    /// The step encountered a failure during execution.
    Failed,
    /// The step failed, but the failure was ignored by policy (e.g. continue-on-error).
    FailedIgnored,
    /// The step was skipped because conditions were not met.
    Skipped,
    /// The step is paused and waiting for an external event or approval.
    WaitingForEvent,
    /// The step was aborted, typically due to the run being cancelled.
    Aborted,
    /// The step's runner went offline while it was executing.
    LostZombie,
}

/// Represents the execution instance of a specific step in a workflow.
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow, ToSchema)]
pub struct StepInstance {
    /// Unique identifier for this execution of the step.
    pub id: StepInstanceId,
    /// Associated workflow run ID.
    pub run_id: RunId,
    /// The name assigned to the step in the workflow definition.
    pub step_name: String,
    /// The type of step (e.g., 'docker', 'wasm', 'approval').
    pub step_type: String,
    /// Current execution status of the step.
    pub status: StepStatus,
    /// The loop index if this step is part of an iteration.
    pub iteration_index: Option<i32>,
    /// Identifier of the runner executing this step, if assigned.
    pub runner_id: Option<String>,
    /// The affinity context key used to group steps on the same runner.
    pub affinity_context: Option<String>, // For shared/locked affinity
    /// Timestamp when the step began executing.
    pub started_at: Option<DateTime<Utc>>,
    /// Timestamp when the step finished executing.
    pub finished_at: Option<DateTime<Utc>>,
    /// The system exit code returned by the step execution, if applicable.
    pub exit_code: Option<i32>,
    /// Optional error message if the step failed.
    pub error: Option<String>,
    /// The raw DSL specification block for this step.
    pub spec: Value,
    /// The resolved parameters passed to the step runner.
    pub params: Value,
    /// Timestamp when the step instance was created.
    pub created_at: DateTime<Utc>,
}

/// A key-value output generated by a step execution.
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow, ToSchema)]
pub struct StepOutput {
    /// Associated step instance ID that generated the output.
    pub step_instance_id: StepInstanceId,
    /// The name of the output key.
    pub key: String,
    /// The JSON value of the output.
    pub value: Value,
    /// Whether this output contains sensitive data that should be redacted.
    pub is_sensitive: bool,
}

/// A historical record of a status transition for a step instance.
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow, ToSchema)]
pub struct StepStatusHistory {
    /// Unique identifier for the history record.
    pub id: i64,
    /// Associated step instance ID.
    pub step_instance_id: StepInstanceId,
    /// The status the step transitioned into.
    pub status: StepStatus,
    /// Timestamp when the status transition occurred.
    pub created_at: DateTime<Utc>,
}
