//! Model capability management — CRUD.

use chrono::Utc;
use db::database::AppDatabase;
use models::agents::CapabilityType;
use models::agents::model_capability;
use sea_orm::*;

use crate::error::AgentError;

#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct CreateModelCapabilityRequest {
    pub model_version_id: i64,
    pub capability: String,
    #[serde(default)]
    pub is_supported: bool,
}

#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct UpdateModelCapabilityRequest {
    pub is_supported: Option<bool>,
}

#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
pub struct ModelCapabilityResponse {
    pub id: i64,
    pub model_version_id: i64,
    pub capability: String,
    pub is_supported: bool,
    pub created_at: chrono::DateTime<Utc>,
}

impl From<model_capability::Model> for ModelCapabilityResponse {
    fn from(mc: model_capability::Model) -> Self {
        Self {
            id: mc.id,
            model_version_id: mc.model_version_id,
            capability: mc.capability,
            is_supported: mc.is_supported,
            created_at: mc.created_at,
        }
    }
}

pub async fn list_capabilities(
    db: &AppDatabase,
    model_version_id: i64,
) -> Result<Vec<ModelCapabilityResponse>, AgentError> {
    let caps = model_capability::Entity::find()
        .filter(model_capability::Column::ModelVersionId.eq(model_version_id))
        .order_by_asc(model_capability::Column::Capability)
        .all(db)
        .await?;
    Ok(caps.into_iter().map(ModelCapabilityResponse::from).collect())
}

pub async fn get_capability(
    db: &AppDatabase,
    id: i64,
) -> Result<ModelCapabilityResponse, AgentError> {
    let cap = model_capability::Entity::find_by_id(id)
        .one(db)
        .await?
        .ok_or_else(|| AgentError::NotFound(format!("Capability record not found: {}", id)))?;
    Ok(ModelCapabilityResponse::from(cap))
}

pub async fn create_capability(
    db: &AppDatabase,
    request: CreateModelCapabilityRequest,
) -> Result<ModelCapabilityResponse, AgentError> {
    let _ = request
        .capability
        .parse::<CapabilityType>()
        .map_err(|_| AgentError::InvalidInput {
            field: "capability".into(),
            reason: "Invalid capability type".into(),
        })?;

    let now = Utc::now();
    let active = model_capability::ActiveModel {
        model_version_id: Set(request.model_version_id),
        capability: Set(request.capability),
        is_supported: Set(request.is_supported),
        created_at: Set(now),
        ..Default::default()
    };
    let cap = active.insert(db).await?;
    Ok(ModelCapabilityResponse::from(cap))
}

pub async fn update_capability(
    db: &AppDatabase,
    id: i64,
    request: UpdateModelCapabilityRequest,
) -> Result<ModelCapabilityResponse, AgentError> {
    let cap = model_capability::Entity::find_by_id(id)
        .one(db)
        .await?
        .ok_or_else(|| AgentError::NotFound(format!("Capability record not found: {}", id)))?;

    let mut active: model_capability::ActiveModel = cap.into();
    if let Some(is_supported) = request.is_supported {
        active.is_supported = Set(is_supported);
    }

    let cap = active.update(db).await?;
    Ok(ModelCapabilityResponse::from(cap))
}

pub async fn delete_capability(db: &AppDatabase, id: i64) -> Result<(), AgentError> {
    model_capability::Entity::delete_by_id(id).exec(db).await?;
    Ok(())
}
