//! List and retrieve project skills.

use crate::AppService;
use crate::error::AppError;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder};
use serde::{Deserialize, Serialize};
use session::Session;
use utoipa::ToSchema;

#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct SkillResponse {
    pub id: i64,
    pub project_uuid: String,
    pub slug: String,
    pub name: String,
    pub description: Option<String>,
    pub source: String,
    pub repo_id: Option<String>,
    pub commit_sha: Option<String>,
    pub blob_hash: Option<String>,
    pub content: String,
    pub metadata: serde_json::Value,
    pub enabled: bool,
    pub created_by: Option<String>,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl From<models::projects::project_skill::Model> for SkillResponse {
    fn from(s: models::projects::project_skill::Model) -> Self {
        Self {
            id: s.id,
            project_uuid: s.project_uuid.to_string(),
            slug: s.slug,
            name: s.name,
            description: s.description,
            source: s.source,
            repo_id: s.repo_id.map(|id| id.to_string()),
            commit_sha: s.commit_sha,
            blob_hash: s.blob_hash,
            content: s.content,
            metadata: s.metadata,
            enabled: s.enabled,
            created_by: s.created_by.map(|id| id.to_string()),
            created_at: s.created_at,
            updated_at: s.updated_at,
        }
    }
}

#[derive(Debug, Clone, Deserialize, utoipa::IntoParams)]
pub struct SkillListQuery {
    pub source: Option<String>,
    pub enabled: Option<bool>,
}

impl AppService {
    /// List all skills registered to a project.
    pub async fn skill_list(
        &self,
        project_uuid: String,
        query: SkillListQuery,
        _ctx: &Session,
    ) -> Result<Vec<SkillResponse>, AppError> {
        let project_id = uuid::Uuid::parse_str(&project_uuid)
            .map_err(|_| AppError::BadRequest("Invalid project UUID".to_string()))?;

        use models::projects::project_skill::Column as C;
        let mut q = models::projects::project_skill::Entity::find()
            .filter(C::ProjectUuid.eq(project_id))
            .order_by_asc(C::Name);

        if let Some(source) = &query.source {
            q = q.filter(C::Source.eq(source.clone()));
        }
        if let Some(enabled) = query.enabled {
            q = q.filter(C::Enabled.eq(enabled));
        }

        let skills = q.all(&self.db).await?;
        Ok(skills.into_iter().map(SkillResponse::from).collect())
    }

    /// Get a single skill by slug within a project.
    pub async fn skill_get(
        &self,
        project_uuid: String,
        slug: String,
        _ctx: &Session,
    ) -> Result<SkillResponse, AppError> {
        let project_id = uuid::Uuid::parse_str(&project_uuid)
            .map_err(|_| AppError::BadRequest("Invalid project UUID".to_string()))?;

        use models::projects::project_skill::Column as C;
        let skill = models::projects::project_skill::Entity::find()
            .filter(C::ProjectUuid.eq(project_id))
            .filter(C::Slug.eq(slug))
            .one(&self.db)
            .await?
            .ok_or_else(|| AppError::NotFound("Skill not found".to_string()))?;

        Ok(SkillResponse::from(skill))
    }
}
