//! Shared types used in both requests and responses.

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

// ============================================================================
// Observation Types (Hosted Mode)
// ============================================================================

/// A single observation from an Aphoria scan.
///
/// Observations are Tier 4 (Community) assertions representing what
/// the code actually does, enabling drift detection and pattern analysis.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ObservationDto {
    /// The subject (concept path, e.g., "code://rust/myapp/tls").
    pub subject: String,

    /// The predicate being claimed (e.g., "enabled").
    pub predicate: String,

    /// The object value.
    pub object: ObservationValueDto,

    /// Confidence score (0.0 to 1.0).
    #[schema(minimum = 0.0, maximum = 1.0)]
    pub confidence: f32,

    /// Source hash (hex-encoded BLAKE3).
    pub source_hash: String,

    /// Agent signatures vouching for this observation.
    pub signatures: Vec<ObservationSignatureDto>,

    /// Unix timestamp when the observation was made.
    pub timestamp: u64,

    /// Source metadata as JSON string (file, line, matched_text, etc.).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_metadata: Option<String>,
}

/// Object value types for observations.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", content = "value")]
pub enum ObservationValueDto {
    /// Textual value
    Text(String),
    /// Numeric value
    Number(f64),
    /// Boolean value
    Boolean(bool),
    /// Entity reference
    Reference(String),
}

/// Signature entry for an observation.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ObservationSignatureDto {
    /// Agent's public key (hex-encoded, 64 chars = 32 bytes).
    pub agent_id: String,
    /// Signature bytes (hex-encoded, 128 chars = 64 bytes).
    pub signature: String,
    /// Timestamp of signature.
    pub timestamp: u64,
    /// Signature version.
    pub version: u8,
}

// ============================================================================
// Community Corpus Types
// ============================================================================

/// An anonymized observation for community corpus contribution.
///
/// Critical privacy constraints:
/// - Subject path must have project segment wildcarded (e.g., `code://rust/*/tls`)
/// - No file paths, line numbers, or source code snippets
/// - anon_hash is computed from (subject, predicate, value) only
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CommunityObservationDto {
    /// Wildcarded subject path (e.g., `code://rust/*/tls/cert_verification`).
    pub subject: String,

    /// The predicate (e.g., "enabled", "min_version").
    pub predicate: String,

    /// The extracted value.
    pub object: CommunityValueDto,

    /// Confidence of extraction (0.0 to 1.0).
    #[schema(minimum = 0.0, maximum = 1.0)]
    pub confidence: f32,

    /// Hash of (subject, predicate, value) ONLY - for deduplication.
    /// CRITICAL: Must NOT include file, line, or matched_text.
    pub anon_hash: String,

    /// Timestamp rounded to the nearest hour (for k-anonymity).
    pub timestamp_hour: u64,
}

/// Value types for community observations.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", content = "value")]
pub enum CommunityValueDto {
    /// Textual value
    Text(String),
    /// Numeric value
    Number(f64),
    /// Boolean value
    Boolean(bool),
}

// ============================================================================
// Scan Finding Types
// ============================================================================

/// A single finding from the scan.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct FindingDto {
    /// The concept path of the claim.
    pub concept_path: String,

    /// The predicate being claimed.
    pub predicate: String,

    /// The value found in code.
    pub code_value: String,

    /// Source file path.
    pub file: String,

    /// Line number in the source file.
    pub line: usize,

    /// Conflict score (0.0 to 1.0).
    pub conflict_score: f32,

    /// Verdict: "BLOCK", "FLAG", "PASS", "ACK".
    pub verdict: String,

    /// Sources that conflict with this claim.
    pub conflicts: Vec<ConflictingSourceDto>,

    /// Acknowledgment info if this conflict was acknowledged.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub acknowledgment: Option<AcknowledgmentDto>,

    /// Debug trace (if debug mode enabled).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub trace: Option<ConflictTraceDto>,
}

/// A source that conflicts with a code claim.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ConflictingSourceDto {
    /// The concept path of the authoritative source.
    pub path: String,

    /// The source class (tier name).
    pub source_class: String,

    /// The authoritative value.
    pub value: String,

    /// RFC/OWASP citation if applicable.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub citation: Option<String>,

    /// Policy source info if from a Trust Pack.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub policy_source: Option<PolicySourceDto>,
}

/// Information about a Trust Pack that provided a policy assertion.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PolicySourceDto {
    /// Name of the Trust Pack.
    pub pack_name: String,

    /// Version of the Trust Pack.
    pub pack_version: String,

    /// First 8 hex characters of the issuer's public key.
    pub issuer_hex: String,
}

/// Acknowledgment information for a conflict.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AcknowledgmentDto {
    /// When the acknowledgment was made.
    pub timestamp: String,

    /// Who made the acknowledgment.
    pub by: String,

    /// The reason given.
    pub reason: String,
}

/// Debug trace explaining the conflict resolution logic.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ConflictTraceDto {
    /// The code claim that triggered the conflict.
    pub code_claim: String,

    /// The authoritative assertion that matched.
    pub authority_match: String,

    /// The tier of the authoritative source.
    pub authority_tier: String,

    /// The resolution explanation.
    pub resolution: String,
}

/// Summary counts for a scan.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ScanSummaryDto {
    /// Total findings.
    pub total: usize,

    /// Findings with BLOCK verdict.
    pub blocked: usize,

    /// Findings with FLAG verdict.
    pub flagged: usize,

    /// Findings with PASS verdict.
    pub passed: usize,

    /// Findings with ACK verdict.
    pub acknowledged: usize,
}

/// A pattern from the community corpus.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PatternDto {
    /// The anonymized subject path.
    pub subject: String,

    /// The predicate.
    pub predicate: String,

    /// The value (display string).
    pub value: String,

    /// Number of distinct projects reporting this pattern.
    pub project_count: u64,

    /// Total number of observations.
    pub observation_count: u64,

    /// Unix timestamp of first observation.
    pub first_seen: u64,

    /// Unix timestamp of most recent observation.
    pub last_seen: u64,
}
