use crate::issues::types::IssueAuthor;
use crate::non_empty;
use model::ai::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiProviderResponse {
    #[schema(value_type = String)]
    pub id: uuid::Uuid,
    pub name: String,
    pub base_url: Option<String>,
    pub website_url: Option<String>,
    pub logo_url: Option<String>,
    pub enabled: bool,
    #[schema(value_type = String)]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[schema(value_type = String)]
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl From<AiProviderModel> for AiProviderResponse {
    fn from(p: AiProviderModel) -> Self {
        AiProviderResponse {
            id: p.id,
            name: p.name,
            base_url: non_empty(p.base_url.unwrap_or_default()),
            website_url: non_empty(p.website_url.unwrap_or_default()),
            logo_url: non_empty(p.logo_url.unwrap_or_default()),
            enabled: p.enabled,
            created_at: p.created_at,
            updated_at: p.updated_at,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiModelListItem {
    #[schema(value_type = String)]
    pub id: uuid::Uuid,
    pub name: String,
    pub display_name: String,
    pub description: Option<String>,
    pub modality: String,
    pub provider_name: String,
    pub provider_logo_url: Option<String>,
    pub context_window: Option<i32>,
    pub input_token_limit: Option<i32>,
    pub output_token_limit: Option<i32>,
    pub enabled: bool,
    #[schema(value_type = String)]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[schema(value_type = String)]
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiModelResponse {
    #[schema(value_type = String)]
    pub id: uuid::Uuid,
    pub name: String,
    pub display_name: String,
    pub description: Option<String>,
    pub modality: String,
    pub context_window: Option<i32>,
    pub input_token_limit: Option<i32>,
    pub output_token_limit: Option<i32>,
    pub enabled: bool,
    pub public: bool,
    pub provider_name: String,
    pub provider_logo_url: Option<String>,
    pub card: Option<AiModelCardResponse>,
    pub versions: Vec<AiModelVersionResponse>,
    pub tags: Vec<String>,
    pub like_count: i64,
    #[schema(value_type = String)]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[schema(value_type = String)]
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiModelCardResponse {
    pub overview: Option<String>,
    pub strengths: Option<String>,
    pub limitations: Option<String>,
    pub safety_notes: Option<String>,
    pub eval_summary: Option<String>,
    pub metadata: Option<String>,
}

impl From<AiModelCardModel> for AiModelCardResponse {
    fn from(c: AiModelCardModel) -> Self {
        AiModelCardResponse {
            overview: non_empty(c.overview.unwrap_or_default()),
            strengths: non_empty(c.strengths.unwrap_or_default()),
            limitations: non_empty(c.limitations.unwrap_or_default()),
            safety_notes: non_empty(c.safety_notes.unwrap_or_default()),
            eval_summary: non_empty(c.eval_summary.unwrap_or_default()),
            metadata: non_empty(c.metadata.unwrap_or_default()),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiModelVersionResponse {
    #[schema(value_type = String)]
    pub id: uuid::Uuid,
    pub version: String,
    pub provider_model_name: String,
    pub input_price_per_million: Option<String>,
    pub output_price_per_million: Option<String>,
    pub cached_input_price_per_million: Option<String>,
    pub training_cutoff: Option<String>,
    #[schema(value_type = Option<String>)]
    pub released_at: Option<chrono::DateTime<chrono::Utc>>,
    #[schema(value_type = Option<String>)]
    pub deprecated_at: Option<chrono::DateTime<chrono::Utc>>,
    pub enabled: bool,
}

impl From<AiModelVersionModel> for AiModelVersionResponse {
    fn from(v: AiModelVersionModel) -> Self {
        AiModelVersionResponse {
            id: v.id,
            version: v.version,
            provider_model_name: v.provider_model_name,
            input_price_per_million: v
                .input_price_per_million
                .map(|d| d.to_string()),
            output_price_per_million: v
                .output_price_per_million
                .map(|d| d.to_string()),
            cached_input_price_per_million: v
                .cached_input_price_per_million
                .map(|d| d.to_string()),
            training_cutoff: v.training_cutoff,
            released_at: v.released_at,
            deprecated_at: v.deprecated_at,
            enabled: v.enabled,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiDiscussionResponse {
    #[schema(value_type = String)]
    pub id: uuid::Uuid,
    pub author: IssueAuthor,
    pub parent: Option<uuid::Uuid>,
    pub body: String,
    #[schema(value_type = String)]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[schema(value_type = String)]
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct AiLikeResponse {
    pub user: IssueAuthor,
    #[schema(value_type = String)]
    pub created_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, Deserialize, utoipa::IntoParams)]
pub struct AiModelFilter {
    pub enabled: Option<bool>,
    pub provider: Option<uuid::Uuid>,
    pub modality: Option<String>,
    pub name: Option<String>,
}
