//! AI provider management — CRUD for model providers.
//!
//! All functions take `&DatabaseConnection` instead of `&AppService`
//! so they can live in the agent crate.

use chrono::Utc;
use db::database::AppDatabase;
use models::agents::model_provider;
use models::agents::{ModelStatus, model_provider::Entity as ProviderEntity};
use sea_orm::*;
use uuid::Uuid;

use crate::error::AgentError;

#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct CreateProviderRequest {
    pub name: String,
    pub display_name: String,
    pub website: Option<String>,
}

#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct UpdateProviderRequest {
    pub display_name: Option<String>,
    pub website: Option<String>,
    pub status: Option<String>,
}

#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
pub struct ProviderResponse {
    pub id: Uuid,
    pub name: String,
    pub display_name: String,
    pub website: Option<String>,
    pub status: String,
    pub created_at: chrono::DateTime<Utc>,
    pub updated_at: chrono::DateTime<Utc>,
}

impl From<model_provider::Model> for ProviderResponse {
    fn from(p: model_provider::Model) -> Self {
        Self {
            id: p.id,
            name: p.name,
            display_name: p.display_name,
            website: p.website,
            status: p.status,
            created_at: p.created_at,
            updated_at: p.updated_at,
        }
    }
}

/// List all providers ordered by display name.
pub async fn list_providers(db: &AppDatabase) -> Result<Vec<ProviderResponse>, AgentError> {
    let providers = ProviderEntity::find()
        .order_by_asc(model_provider::Column::DisplayName)
        .all(db)
        .await?;
    Ok(providers.into_iter().map(ProviderResponse::from).collect())
}

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

/// Create a new provider.
pub async fn create_provider(
    db: &AppDatabase,
    request: CreateProviderRequest,
) -> Result<ProviderResponse, AgentError> {
    let now = Utc::now();
    let active = model_provider::ActiveModel {
        id: Set(Uuid::now_v7()),
        name: Set(request.name),
        display_name: Set(request.display_name),
        website: Set(request.website),
        status: Set(ModelStatus::Active.to_string()),
        created_at: Set(now),
        updated_at: Set(now),
        ..Default::default()
    };
    let model = active.insert(db).await?;
    Ok(ProviderResponse::from(model))
}

/// Update an existing provider.
pub async fn update_provider(
    db: &AppDatabase,
    id: Uuid,
    request: UpdateProviderRequest,
) -> Result<ProviderResponse, AgentError> {
    let provider = ProviderEntity::find_by_id(id)
        .one(db)
        .await?
        .ok_or_else(|| AgentError::NotFound(format!("Provider not found: {}", id)))?;

    let mut active: model_provider::ActiveModel = provider.into();
    if let Some(display_name) = request.display_name {
        active.display_name = Set(display_name);
    }
    if let Some(website) = request.website {
        active.website = Set(Some(website));
    }
    if let Some(status) = request.status {
        active.status = Set(status);
    }
    active.updated_at = Set(Utc::now());

    let model = active.update(db).await?;
    Ok(ProviderResponse::from(model))
}

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