//! Model version management — CRUD.
//!
//! All functions take `&DatabaseConnection` instead of `&AppService`.

use chrono::Utc;
use db::database::AppDatabase;
use models::agents::model_version;
use models::agents::{
    ModelStatus,
    model_version::{Column as MVColumn, Entity as MVEntity, Model as ModelVersionModel},
};
use sea_orm::*;
use uuid::Uuid;

use crate::error::AgentError;

#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct CreateModelVersionRequest {
    pub model_id: Uuid,
    pub version: String,
    pub release_date: Option<chrono::DateTime<Utc>>,
    pub change_log: Option<String>,
    #[serde(default)]
    pub is_default: bool,
}

#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct UpdateModelVersionRequest {
    pub version: Option<String>,
    pub release_date: Option<chrono::DateTime<Utc>>,
    pub change_log: Option<String>,
    pub is_default: Option<bool>,
    pub status: Option<String>,
}

#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
pub struct ModelVersionResponse {
    pub id: Uuid,
    pub model_id: Uuid,
    pub version: String,
    pub release_date: Option<chrono::DateTime<Utc>>,
    pub change_log: Option<String>,
    pub is_default: bool,
    pub status: String,
    pub created_at: chrono::DateTime<Utc>,
}

impl From<ModelVersionModel> for ModelVersionResponse {
    fn from(mv: ModelVersionModel) -> Self {
        Self {
            id: mv.id,
            model_id: mv.model_id,
            version: mv.version,
            release_date: mv.release_date,
            change_log: mv.change_log,
            is_default: mv.is_default,
            status: mv.status,
            created_at: mv.created_at,
        }
    }
}

/// List model versions, optionally filtered by model.
pub async fn list_versions(
    db: &AppDatabase,
    model_id: Option<Uuid>,
) -> Result<Vec<ModelVersionResponse>, AgentError> {
    let mut query = MVEntity::find().order_by_asc(MVColumn::Version);
    if let Some(mid) = model_id {
        query = query.filter(MVColumn::ModelId.eq(mid));
    }
    let versions = query.all(db).await?;
    Ok(versions.into_iter().map(ModelVersionResponse::from).collect())
}

/// Get a single version by ID.
pub async fn get_version(
    db: &AppDatabase,
    id: Uuid,
) -> Result<ModelVersionResponse, AgentError> {
    let version = MVEntity::find_by_id(id)
        .one(db)
        .await?
        .ok_or_else(|| AgentError::NotFound(format!("Model version not found: {}", id)))?;
    Ok(ModelVersionResponse::from(version))
}

/// Create a new model version.
pub async fn create_version(
    db: &AppDatabase,
    request: CreateModelVersionRequest,
) -> Result<ModelVersionResponse, AgentError> {
    let now = Utc::now();
    let active = model_version::ActiveModel {
        id: Set(Uuid::now_v7()),
        model_id: Set(request.model_id),
        version: Set(request.version),
        release_date: Set(request.release_date),
        change_log: Set(request.change_log),
        is_default: Set(request.is_default),
        status: Set(ModelStatus::Active.to_string()),
        created_at: Set(now),
        ..Default::default()
    };
    let version = active.insert(db).await?;
    Ok(ModelVersionResponse::from(version))
}

/// Update an existing model version.
pub async fn update_version(
    db: &AppDatabase,
    id: Uuid,
    request: UpdateModelVersionRequest,
) -> Result<ModelVersionResponse, AgentError> {
    let version = MVEntity::find_by_id(id)
        .one(db)
        .await?
        .ok_or_else(|| AgentError::NotFound(format!("Model version not found: {}", id)))?;

    let mut active: model_version::ActiveModel = version.into();
    if let Some(v) = request.version {
        active.version = Set(v);
    }
    if let Some(v) = request.release_date {
        active.release_date = Set(Some(v));
    }
    if let Some(v) = request.change_log {
        active.change_log = Set(Some(v));
    }
    if let Some(v) = request.is_default {
        active.is_default = Set(v);
    }
    if let Some(v) = request.status {
        active.status = Set(v);
    }

    let version = active.update(db).await?;
    Ok(ModelVersionResponse::from(version))
}

/// Delete a model version by ID.
pub async fn delete_version(db: &AppDatabase, id: Uuid) -> Result<(), AgentError> {
    MVEntity::delete_by_id(id).exec(db).await?;
    Ok(())
}
