//! Data models for the Axoniac API.

use serde::{Deserialize, Serialize};
use uuid::Uuid;

// ── Tenant ─────────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Tenant {
    pub id: Uuid,
    #[serde(default)]
    pub user_id: Uuid,
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub slug: String,
    #[serde(default)]
    pub tool_set: Option<String>,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}

// ── Agent Packs ────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct AgentPack {
    pub id: Uuid,
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub definition: serde_json::Value,
    #[serde(default)]
    pub version: Option<String>,
    #[serde(default)]
    pub created_by: Option<Uuid>,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub content_hash: Option<String>,
    #[serde(default)]
    pub soul_hash: Option<String>,
    #[serde(default)]
    pub category: Option<String>,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub parent_hash: Option<String>,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct AgentPackInstallation {
    pub id: Uuid,
    pub tenant_id: Uuid,
    pub agent_pack_hash: String,

    #[cfg(feature = "chrono")]
    pub installed_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub installed_at: Option<String>,
}

// ── Provision Pack ─────────────────────────────────────

/// Input for provisioning a complete agent pack (soul + personas + pack).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvisionPackRequest {
    pub soul: SoulInput,
    pub personas: Vec<PersonaInput>,
    pub pack: PackInput,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SoulInput {
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PersonaInput {
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PackInput {
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub version: Option<String>,
    #[serde(default = "default_definition")]
    pub definition: serde_json::Value,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub parent_hash: Option<String>,
}

fn default_definition() -> serde_json::Value {
    serde_json::json!({})
}

/// Response from provisioning a pack.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvisionResult {
    pub content_hash: String,
    pub pack_id: Uuid,
    pub soul_hash: String,
    #[serde(default)]
    pub persona_hashes: std::collections::HashMap<String, String>,
    #[serde(default)]
    pub created: bool,
}

// ── Memories ───────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Memory {
    pub id: Uuid,
    #[serde(default)]
    pub user_id: Uuid,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub memory_type: String,
    #[serde(default)]
    pub importance: f64,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub source: Option<String>,
    #[serde(default)]
    pub access_count: i32,

    #[cfg(feature = "chrono")]
    pub last_accessed: Option<chrono::DateTime<chrono::Utc>>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub last_accessed: Option<String>,

    #[cfg(feature = "chrono")]
    pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub expires_at: Option<String>,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}

// ── Skills ──────────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Skill {
    pub id: Uuid,
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub version: Option<String>,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub content_hash: Option<String>,
    #[serde(default)]
    pub parent_hash: Option<String>,
    #[serde(default)]
    pub enabled: bool,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}

// ── Agent Pack With Stats (search result) ───────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentPackWithStats {
    pub id: Uuid,
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub definition: serde_json::Value,
    #[serde(default)]
    pub version: Option<String>,
    #[serde(default)]
    pub created_by: Option<Uuid>,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub content_hash: Option<String>,
    #[serde(default)]
    pub soul_hash: Option<String>,
    #[serde(default)]
    pub category: Option<String>,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub parent_hash: Option<String>,
    #[serde(default)]
    pub install_count: i64,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}

// ── Agent Export/Import ───────────────────────────────

/// Exported agent configuration (pack + extras).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentExport {
    pub agent_pack: Option<AgentPack>,
    pub agent_extras: AgentExtrasExport,
}

/// The extras portion of an agent export.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentExtrasExport {
    pub skills: Vec<AgentExtrasSkillExport>,
    pub hooks: Vec<AgentExtrasHookExport>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentExtrasSkillExport {
    pub name: String,
    pub description: String,
    pub content: String,
    #[serde(default)]
    pub content_hash: Option<String>,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub enabled: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentExtrasHookExport {
    pub event: String,
    #[serde(default)]
    pub options: serde_json::Value,
    #[serde(default)]
    pub position: i32,
    #[serde(default)]
    pub persona: Option<AgentExtrasHookPersonaRef>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentExtrasHookPersonaRef {
    pub name: String,
    #[serde(default)]
    pub content_hash: Option<String>,
}

// ── Bundle ─────────────────────────────────────────────

/// A resolved agent pack bundle with all components.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentPackBundle {
    #[serde(default)]
    pub pack: Option<serde_json::Value>,
    #[serde(default)]
    pub soul: Option<serde_json::Value>,
    #[serde(default)]
    pub personas: serde_json::Value,
    #[serde(default)]
    pub skills: Vec<serde_json::Value>,
    #[serde(default)]
    pub hook_options: serde_json::Value,
}

// ── Souls & Personas ───────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Soul {
    pub id: Uuid,
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub content_hash: Option<String>,
    #[serde(default)]
    pub parent_hash: Option<String>,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Persona {
    pub id: Uuid,
    pub name: String,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub tags: Option<Vec<String>>,
    #[serde(default)]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub content_hash: Option<String>,
    #[serde(default)]
    pub parent_hash: Option<String>,

    #[cfg(feature = "chrono")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    #[cfg(feature = "chrono")]
    pub updated_at: chrono::DateTime<chrono::Utc>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub created_at: Option<String>,
    #[cfg(not(feature = "chrono"))]
    #[serde(default)]
    pub updated_at: Option<String>,
}
