use crate::AppService;
use crate::error::AppError;
use chrono::Utc;
use models::agents::model_version;
use models::agents::{
    ModelStatus,
    model_version::{Column as MVColumn, Entity as MVEntity, Model as ModelVersionModel},
};
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
use utoipa::ToSchema;
use uuid::Uuid;

use super::provider::require_system_caller;

#[derive(Debug, Clone, Deserialize, 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, Deserialize, 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, Serialize, 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,
        }
    }
}

impl AppService {
    pub async fn agent_model_version_list(
        &self,
        model_id: Option<Uuid>,
        _ctx: &Session,
    ) -> Result<Vec<ModelVersionResponse>, AppError> {
        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(&self.db).await?;
        Ok(versions
            .into_iter()
            .map(ModelVersionResponse::from)
            .collect())
    }

    pub async fn agent_model_version_get(
        &self,
        id: Uuid,
        _ctx: &Session,
    ) -> Result<ModelVersionResponse, AppError> {
        let version = MVEntity::find_by_id(id)
            .one(&self.db)
            .await?
            .ok_or(AppError::NotFound("Model version not found".to_string()))?;
        Ok(ModelVersionResponse::from(version))
    }

    pub async fn agent_model_version_create(
        &self,
        request: CreateModelVersionRequest,
        ctx: &Session,
    ) -> Result<ModelVersionResponse, AppError> {
        require_system_caller(ctx)?;

        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(&self.db).await?;
        Ok(ModelVersionResponse::from(version))
    }

    pub async fn agent_model_version_update(
        &self,
        id: Uuid,
        request: UpdateModelVersionRequest,
        ctx: &Session,
    ) -> Result<ModelVersionResponse, AppError> {
        require_system_caller(ctx)?;

        let version = MVEntity::find_by_id(id)
            .one(&self.db)
            .await?
            .ok_or(AppError::NotFound("Model version not found".to_string()))?;

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

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

    pub async fn agent_model_version_delete(
        &self,
        id: Uuid,
        ctx: &Session,
    ) -> Result<(), AppError> {
        require_system_caller(ctx)?;
        MVEntity::delete_by_id(id).exec(&self.db).await?;
        Ok(())
    }
}
