//! Enum DTOs and their conversions to/from internal types.

use serde::{Deserialize, Serialize};
use stemedb_core::types::{
    LifecycleStage, ObjectValue, SignatureEntry, SourceClass, SupersessionType,
};
use utoipa::ToSchema;

// ============================================================================
// Enum DTOs
// ============================================================================

/// Object value in an assertion.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", content = "value")]
pub enum ObjectValueDto {
    /// Text string value
    Text(String),

    /// Numeric value (float)
    Number(f64),

    /// Boolean value
    Boolean(bool),

    /// Reference to another entity
    Reference(String),
}

/// Lifecycle stage of an assertion.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "PascalCase")]
pub enum LifecycleDto {
    /// Initial proposal, idea, or RFC
    Proposed,

    /// Under active review or debate
    UnderReview,

    /// Accepted as current truth
    Approved,

    /// Was true, now superseded
    Deprecated,

    /// Considered and explicitly declined
    Rejected,
}

/// Source authority tier classification.
///
/// Sources are tiered from most authoritative (Regulatory, Tier 0) to
/// least authoritative (Anecdotal, Tier 5). This enables indexing by
/// tier and tier-based decay rates.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "PascalCase")]
pub enum SourceClassDto {
    /// Tier 0: Regulatory bodies (FDA, EMA, WHO)
    Regulatory,

    /// Tier 1: Clinical trials, peer-reviewed research
    Clinical,

    /// Tier 2: Observational studies, real-world evidence
    Observational,

    /// Tier 3: Expert opinions, medical guidelines
    Expert,

    /// Tier 4: Curated community knowledge
    Community,

    /// Tier 5: Individual reports, testimonials, social media
    Anecdotal,
}

/// Type of supersession (epoch or assertion).
///
/// Determines how old knowledge should be treated when superseded.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "PascalCase")]
pub enum SupersessionTypeDto {
    /// Old assertion was factually incorrect and should be hidden/ignored.
    Invalidate,

    /// Old assertion was correct at the time but now outdated.
    Temporal,

    /// Old assertion was a simplification; new one is more precise.
    Refinement,

    /// Old assertion needs human review before trusting.
    RequiresReview,

    /// New assertion adds context without invalidating the old one.
    Additive,
}

/// Lens strategy for conflict resolution.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "PascalCase")]
pub enum LensDto {
    /// Latest timestamp wins
    Recency,

    /// Most common object value
    Consensus,

    /// Highest assertion confidence field wins.
    /// Use this when assertions have meaningful self-declared confidence scores.
    Confidence,

    /// Weighted by agent reputation (TrustRank).
    /// This is the real "authority" lens - uses agent history and reputation.
    /// Equivalent to TrustAwareAuthority.
    Authority,

    /// Highest vote weight from VoteStore
    VoteAwareConsensus,

    /// Weighted by TrustRank reputation.
    /// Same as Authority - both route to TrustAwareAuthorityLens.
    TrustAwareAuthority,

    /// Filters assertions from superseded epochs before applying Recency.
    /// Use when querying across paradigm shifts (e.g., GAAP to IFRS transition).
    /// Assertions from epochs that have been superseded by newer epochs are excluded.
    EpochAware,

    /// Per-source-class consensus with tier-by-tier visibility.
    /// Returns results for each authority tier (Regulatory, Clinical, etc.)
    /// plus an overall winner from the highest-authority tier present.
    /// Use when you need to see "What does the FDA say? What do clinical trials say?"
    LayeredConsensus,

    /// Categorizes assertions by constraint predicates (must_use, forbidden, prefer).
    /// Use for agent pre-flight checks: "What MUST I use? What's FORBIDDEN?"
    /// Predicate patterns: `must_use:*`, `forbidden:*`, `prefer:*`
    Constraints,
}

/// Agent signature entry.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SignatureDto {
    /// Ed25519 public key of the agent (hex-encoded, 32 bytes)
    pub agent_id: String,

    /// Ed25519 signature (hex-encoded, 64 bytes)
    pub signature: String,

    /// Timestamp when the agent signed (Unix epoch)
    pub timestamp: u64,

    /// Signature version (1 = legacy subject:predicate, 2 = content hash). Defaults to 1.
    #[serde(default = "default_version")]
    pub version: Option<u8>,
}

fn default_version() -> Option<u8> {
    Some(1)
}

// ============================================================================
// Conversions: DTOs ↔ Internal Types
// ============================================================================

impl From<ObjectValue> for ObjectValueDto {
    fn from(value: ObjectValue) -> Self {
        match value {
            ObjectValue::Text(s) => ObjectValueDto::Text(s),
            ObjectValue::Number(n) => ObjectValueDto::Number(n),
            ObjectValue::Boolean(b) => ObjectValueDto::Boolean(b),
            ObjectValue::Reference(r) => ObjectValueDto::Reference(r),
        }
    }
}

impl From<ObjectValueDto> for ObjectValue {
    fn from(dto: ObjectValueDto) -> Self {
        match dto {
            ObjectValueDto::Text(s) => ObjectValue::Text(s),
            ObjectValueDto::Number(n) => ObjectValue::Number(n),
            ObjectValueDto::Boolean(b) => ObjectValue::Boolean(b),
            ObjectValueDto::Reference(r) => ObjectValue::Reference(r),
        }
    }
}

impl From<LifecycleStage> for LifecycleDto {
    fn from(stage: LifecycleStage) -> Self {
        match stage {
            LifecycleStage::Proposed => LifecycleDto::Proposed,
            LifecycleStage::UnderReview => LifecycleDto::UnderReview,
            LifecycleStage::Approved => LifecycleDto::Approved,
            LifecycleStage::Deprecated => LifecycleDto::Deprecated,
            LifecycleStage::Rejected => LifecycleDto::Rejected,
        }
    }
}

impl From<LifecycleDto> for LifecycleStage {
    fn from(dto: LifecycleDto) -> Self {
        match dto {
            LifecycleDto::Proposed => LifecycleStage::Proposed,
            LifecycleDto::UnderReview => LifecycleStage::UnderReview,
            LifecycleDto::Approved => LifecycleStage::Approved,
            LifecycleDto::Deprecated => LifecycleStage::Deprecated,
            LifecycleDto::Rejected => LifecycleStage::Rejected,
        }
    }
}

impl From<SupersessionType> for SupersessionTypeDto {
    fn from(stype: SupersessionType) -> Self {
        match stype {
            SupersessionType::Invalidate => SupersessionTypeDto::Invalidate,
            SupersessionType::Temporal => SupersessionTypeDto::Temporal,
            SupersessionType::Refinement => SupersessionTypeDto::Refinement,
            SupersessionType::RequiresReview => SupersessionTypeDto::RequiresReview,
            SupersessionType::Additive => SupersessionTypeDto::Additive,
        }
    }
}

impl From<SupersessionTypeDto> for SupersessionType {
    fn from(dto: SupersessionTypeDto) -> Self {
        match dto {
            SupersessionTypeDto::Invalidate => SupersessionType::Invalidate,
            SupersessionTypeDto::Temporal => SupersessionType::Temporal,
            SupersessionTypeDto::Refinement => SupersessionType::Refinement,
            SupersessionTypeDto::RequiresReview => SupersessionType::RequiresReview,
            SupersessionTypeDto::Additive => SupersessionType::Additive,
        }
    }
}

impl From<SourceClass> for SourceClassDto {
    fn from(sc: SourceClass) -> Self {
        match sc {
            SourceClass::Regulatory => SourceClassDto::Regulatory,
            SourceClass::Clinical => SourceClassDto::Clinical,
            SourceClass::Observational => SourceClassDto::Observational,
            SourceClass::Expert => SourceClassDto::Expert,
            SourceClass::Community => SourceClassDto::Community,
            SourceClass::Anecdotal => SourceClassDto::Anecdotal,
        }
    }
}

impl From<SourceClassDto> for SourceClass {
    fn from(dto: SourceClassDto) -> Self {
        match dto {
            SourceClassDto::Regulatory => SourceClass::Regulatory,
            SourceClassDto::Clinical => SourceClass::Clinical,
            SourceClassDto::Observational => SourceClass::Observational,
            SourceClassDto::Expert => SourceClass::Expert,
            SourceClassDto::Community => SourceClass::Community,
            SourceClassDto::Anecdotal => SourceClass::Anecdotal,
        }
    }
}

impl From<SignatureEntry> for SignatureDto {
    fn from(entry: SignatureEntry) -> Self {
        SignatureDto {
            agent_id: hex::encode(entry.agent_id),
            signature: hex::encode(entry.signature),
            timestamp: entry.timestamp,
            version: Some(entry.version),
        }
    }
}
