// file: kb_lib/src/db/dtos/local_pipeline_diagnostics.rs

//! DTOs for local pipeline diagnostics.

/// Local pipeline diagnostics summary.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalPipelineDiagnosticSummaryDto {
    /// Total persisted chain transactions.
    pub transaction_count: i64,
    /// Total successful chain transactions.
    pub ok_transaction_count: i64,
    /// Total failed chain transactions.
    pub failed_transaction_count: i64,
    /// Total decoded DEX events.
    pub decoded_event_count: i64,
    /// Total decoded DEX trade candidates.
    pub decoded_trade_candidate_count: i64,
    /// Total decoded DEX candle candidates.
    pub decoded_candle_candidate_count: i64,
    /// Whether the local persisted pipeline has no blocking diagnostic issue.
    pub diagnostics_clean: bool,
    /// Number of blocking diagnostic issues.
    ///
    /// This currently includes actionable missing trade events, invalid trade
    /// events, duplicate decoded-event trade rows, and duplicate candle buckets.
    pub blocking_issue_count: i64,
    /// Total decoded DEX events that are trade candidates but have no trade event,
    /// including intentionally ignored failed transactions.
    pub missing_trade_event_count: i64,
    /// Total persisted trade events.
    pub trade_event_count: i64,
    /// Explicit alias for decoded trade candidates without linked trade event.
    pub decoded_trade_candidate_without_trade_event_count: i64,
    /// Trade candidates without linked trade event on successful transactions.
    pub decoded_trade_candidate_without_trade_event_on_ok_transaction_count: i64,
    /// Trade candidates without linked trade event on failed transactions.
    pub decoded_trade_candidate_without_trade_event_on_failed_transaction_count: i64,
    /// Actionable missing trade events on successful transactions.
    pub actionable_missing_trade_event_count: i64,
    /// Ignored missing trade events caused by failed transactions.
    pub ignored_failed_transaction_trade_candidate_count: i64,
    /// Trade candidates without linked trade event and without explicit base/quote payload amounts.
    pub decoded_trade_candidate_without_amount_payload_count: i64,
    /// Total trade events with missing or invalid pricing fields.
    pub invalid_trade_event_count: i64,
    /// Total persisted pair candles.
    pub pair_candle_count: i64,
    /// Real duplicate trade rows grouped by decoded event id.
    pub duplicate_decoded_event_trade_count: i64,
    /// Multi-trade groups sharing the same signature and pair id.
    pub multi_trade_signature_pair_count: i64,
    /// Total duplicate candle buckets.
    pub duplicate_candle_bucket_count: i64,
    /// Total known tokens.
    pub token_count: i64,
    /// Total tokens missing symbol or name.
    pub token_metadata_missing_count: i64,
    /// Total known pools.
    pub pool_count: i64,
    /// Total known pairs.
    pub pair_count: i64,
    /// Total pairs without trade event.
    pub pair_without_trade_count: i64,
    /// Total pairs without candle.
    pub pair_without_candle_count: i64,
    /// Diagnostics grouped by DEX.
    pub dex_summaries: std::vec::Vec<crate::LocalDexDiagnosticSummaryDto>,
    /// Diagnostics grouped by pair.
    pub pair_summaries: std::vec::Vec<crate::LocalPairDiagnosticSummaryDto>,
    /// Diagnostics grouped by decoded event kind.
    pub decoded_event_summaries: std::vec::Vec<crate::LocalDecodedEventDiagnosticSummaryDto>,
    /// Missing trade events grouped by diagnostic reason.
    pub missing_trade_event_reason_summaries:
        std::vec::Vec<crate::LocalMissingTradeEventReasonSummaryDto>,
    /// Total pairs with only non-actionable missing trade events.
    pub non_actionable_pair_count: i64,
    /// Pair summaries for non-actionable missing trade events.
    pub non_actionable_pair_summaries:
        std::vec::Vec<crate::LocalNonActionablePairDiagnosticSummaryDto>,
    /// Samples of decoded trade candidates without linked trade event.
    pub missing_trade_event_samples:
        std::vec::Vec<crate::LocalMissingTradeEventDiagnosticSampleDto>,
    /// Samples of duplicated trade rows by decoded event id.
    pub duplicate_decoded_event_trade_samples:
        std::vec::Vec<crate::LocalDuplicateDecodedEventTradeDiagnosticSampleDto>,
    /// Samples of multi-trade signature/pair groups.
    pub multi_trade_signature_pair_samples:
        std::vec::Vec<crate::LocalMultiTradeSignaturePairDiagnosticSampleDto>,
    /// Samples of pairs without trade.
    pub pair_without_trade_samples: std::vec::Vec<crate::LocalPairGapDiagnosticSampleDto>,
    /// Samples of pairs without candle.
    pub pair_without_candle_samples: std::vec::Vec<crate::LocalPairGapDiagnosticSampleDto>,
}

/// Local DEX diagnostics summary.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalDexDiagnosticSummaryDto {
    /// DEX code or protocol name.
    pub dex_code: std::string::String,
    /// Total known pools for this DEX.
    pub pool_count: i64,
    /// Total known pairs for this DEX.
    pub pair_count: i64,
    /// Total decoded events for this DEX.
    pub decoded_event_count: i64,
    /// Total decoded trade candidates for this DEX.
    pub decoded_trade_candidate_count: i64,
    /// Total decoded candle candidates for this DEX.
    pub decoded_candle_candidate_count: i64,
    /// Total persisted trade events for this DEX.
    pub trade_event_count: i64,
    /// Total persisted candles for this DEX.
    pub pair_candle_count: i64,
}

/// Local pair diagnostics summary.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalPairDiagnosticSummaryDto {
    /// Pair id.
    pub pair_id: i64,
    /// Pool address.
    pub pool_address: std::string::String,
    /// DEX code.
    pub dex_code: std::string::String,
    /// Base token mint.
    pub base_mint: std::string::String,
    /// Base token symbol.
    pub base_symbol: std::option::Option<std::string::String>,
    /// Quote token mint.
    pub quote_mint: std::string::String,
    /// Quote token symbol.
    pub quote_symbol: std::option::Option<std::string::String>,
    /// Pair symbol.
    pub pair_symbol: std::option::Option<std::string::String>,
    /// Total decoded events attached to the pool.
    pub decoded_event_count: i64,
    /// Total decoded trade candidates attached to the pool.
    pub decoded_trade_candidate_count: i64,
    /// Total decoded candle candidates attached to the pool.
    pub decoded_candle_candidate_count: i64,
    /// Total trade events attached to the pair.
    pub trade_event_count: i64,
    /// Total invalid trade events attached to the pair.
    pub invalid_trade_event_count: i64,
    /// Total candle buckets attached to the pair.
    pub pair_candle_count: i64,
    /// Last known price.
    pub last_price_quote_per_base: std::option::Option<f64>,
}

/// Local decoded-event diagnostics summary.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalDecodedEventDiagnosticSummaryDto {
    /// Protocol name.
    pub protocol_name: std::string::String,
    /// Event kind.
    pub event_kind: std::string::String,
    /// Event category.
    pub event_category: std::option::Option<std::string::String>,
    /// Whether payload says this event is a trade candidate.
    pub trade_candidate: std::option::Option<bool>,
    /// Whether payload says this event is a candle candidate.
    pub candle_candidate: std::option::Option<bool>,
    /// Event count.
    pub event_count: i64,
    /// Trade-event count linked to these decoded events.
    pub trade_event_count: i64,
}

/// Missing trade event diagnostics grouped by reason.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalMissingTradeEventReasonSummaryDto {
    /// Diagnostic reason.
    pub reason: std::string::String,
    /// Whether grouped source transactions failed.
    pub transaction_failed: bool,
    /// Whether grouped missing trade events are actionable.
    pub actionable: bool,
    /// Total missing trade events in this group.
    pub event_count: i64,
    /// Total events in this group with an explicit base amount payload.
    pub has_base_amount_payload_count: i64,
    /// Total events in this group with an explicit quote amount payload.
    pub has_quote_amount_payload_count: i64,
    /// Total events in this group with an explicit price payload.
    pub has_price_payload_count: i64,
}

/// Local pair diagnostics for pairs whose missing trade events are non-actionable.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalNonActionablePairDiagnosticSummaryDto {
    /// Pair id.
    pub pair_id: i64,
    /// Pool address.
    pub pool_address: std::string::String,
    /// DEX code.
    pub dex_code: std::string::String,
    /// Base token mint.
    pub base_mint: std::string::String,
    /// Base token symbol.
    pub base_symbol: std::option::Option<std::string::String>,
    /// Quote token mint.
    pub quote_mint: std::string::String,
    /// Quote token symbol.
    pub quote_symbol: std::option::Option<std::string::String>,
    /// Pair symbol.
    pub pair_symbol: std::option::Option<std::string::String>,
    /// Total decoded trade candidates attached to the pool.
    pub decoded_trade_candidate_count: i64,
    /// Total non-actionable missing trade events attached to the pair.
    pub non_actionable_missing_trade_event_count: i64,
    /// Total missing trade candidates caused by failed transactions.
    pub failed_transaction_candidate_count: i64,
    /// Total successful missing trade candidates without token mints.
    pub ok_transaction_without_token_mints_count: i64,
    /// Total successful missing trade candidates without amount payload.
    pub ok_transaction_without_amount_payload_count: i64,
    /// Distinct non-actionable diagnostic reasons seen for this pair.
    pub reason_summary: std::option::Option<std::string::String>,
    /// Total trade events attached to the pair.
    pub trade_event_count: i64,
    /// Total candle buckets attached to the pair.
    pub pair_candle_count: i64,
}

/// Internal flat counter row for local diagnostics.
#[derive(Debug, Clone)]
pub struct LocalPipelineDiagnosticCountersDto {
    /// Total persisted chain transactions.
    pub transaction_count: i64,
    /// Total successful chain transactions.
    pub ok_transaction_count: i64,
    /// Total failed chain transactions.
    pub failed_transaction_count: i64,
    /// Total decoded DEX events.
    pub decoded_event_count: i64,
    /// Total decoded DEX trade candidates.
    pub decoded_trade_candidate_count: i64,
    /// Total decoded DEX candle candidates.
    pub decoded_candle_candidate_count: i64,
    /// Total decoded trade candidates without trade event, including ignored failed transactions.
    pub missing_trade_event_count: i64,
    /// Explicit alias for decoded trade candidates without linked trade event.
    pub decoded_trade_candidate_without_trade_event_count: i64,
    /// Trade candidates without linked trade event on successful transactions.
    pub decoded_trade_candidate_without_trade_event_on_ok_transaction_count: i64,
    /// Trade candidates without linked trade event on failed transactions.
    pub decoded_trade_candidate_without_trade_event_on_failed_transaction_count: i64,
    /// Actionable missing trade events on successful transactions.
    pub actionable_missing_trade_event_count: i64,
    /// Ignored missing trade events caused by failed transactions.
    pub ignored_failed_transaction_trade_candidate_count: i64,
    /// Trade candidates without linked trade event and without explicit base/quote payload amounts.
    pub decoded_trade_candidate_without_amount_payload_count: i64,
    /// Total persisted trade events.
    pub trade_event_count: i64,
    /// Total invalid trade events.
    pub invalid_trade_event_count: i64,
    /// Total persisted candles.
    pub pair_candle_count: i64,
    /// Real duplicate trade rows grouped by decoded event id.
    pub duplicate_decoded_event_trade_count: i64,
    /// Multi-trade groups sharing the same signature and pair id.
    pub multi_trade_signature_pair_count: i64,
    /// Total duplicate candle groups.
    pub duplicate_candle_bucket_count: i64,
    /// Total known tokens.
    pub token_count: i64,
    /// Total tokens missing metadata.
    pub token_metadata_missing_count: i64,
    /// Total known pools.
    pub pool_count: i64,
    /// Total known pairs.
    pub pair_count: i64,
    /// Total pairs with only non-actionable missing trade events.
    pub non_actionable_pair_count: i64,
    /// Total pairs without trade.
    pub pair_without_trade_count: i64,
    /// Total pairs without candle.
    pub pair_without_candle_count: i64,
}

/// SQL row for global local pipeline diagnostic counters.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalPipelineDiagnosticCountersRow {
    pub(crate) transaction_count: i64,
    pub(crate) ok_transaction_count: i64,
    pub(crate) failed_transaction_count: i64,
    pub(crate) decoded_event_count: i64,
    pub(crate) decoded_trade_candidate_count: i64,
    pub(crate) decoded_candle_candidate_count: i64,
    pub(crate) missing_trade_event_count: i64,
    pub(crate) decoded_trade_candidate_without_trade_event_count: i64,
    pub(crate) decoded_trade_candidate_without_trade_event_on_ok_transaction_count: i64,
    pub(crate) decoded_trade_candidate_without_trade_event_on_failed_transaction_count: i64,
    pub(crate) actionable_missing_trade_event_count: i64,
    pub(crate) ignored_failed_transaction_trade_candidate_count: i64,
    pub(crate) decoded_trade_candidate_without_amount_payload_count: i64,
    pub(crate) trade_event_count: i64,
    pub(crate) invalid_trade_event_count: i64,
    pub(crate) pair_candle_count: i64,
    pub(crate) duplicate_decoded_event_trade_count: i64,
    pub(crate) multi_trade_signature_pair_count: i64,
    pub(crate) duplicate_candle_bucket_count: i64,
    pub(crate) token_count: i64,
    pub(crate) token_metadata_missing_count: i64,
    pub(crate) pool_count: i64,
    pub(crate) pair_count: i64,
    pub(crate) non_actionable_pair_count: i64,
    pub(crate) pair_without_trade_count: i64,
    pub(crate) pair_without_candle_count: i64,
}

/// SQL row for local DEX diagnostics.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalDexDiagnosticSummaryRow {
    pub(crate) dex_code: std::string::String,
    pub(crate) pool_count: i64,
    pub(crate) pair_count: i64,
    pub(crate) decoded_event_count: i64,
    pub(crate) decoded_trade_candidate_count: i64,
    pub(crate) decoded_candle_candidate_count: i64,
    pub(crate) trade_event_count: i64,
    pub(crate) pair_candle_count: i64,
}

/// SQL row for local pair diagnostics.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalPairDiagnosticSummaryRow {
    pub(crate) pair_id: i64,
    pub(crate) pool_address: std::string::String,
    pub(crate) dex_code: std::string::String,
    pub(crate) base_mint: std::string::String,
    pub(crate) base_symbol: std::option::Option<std::string::String>,
    pub(crate) quote_mint: std::string::String,
    pub(crate) quote_symbol: std::option::Option<std::string::String>,
    pub(crate) pair_symbol: std::option::Option<std::string::String>,
    pub(crate) decoded_event_count: i64,
    pub(crate) decoded_trade_candidate_count: i64,
    pub(crate) decoded_candle_candidate_count: i64,
    pub(crate) trade_event_count: i64,
    pub(crate) invalid_trade_event_count: i64,
    pub(crate) pair_candle_count: i64,
    pub(crate) last_price_quote_per_base: std::option::Option<f64>,
}

/// SQL row for local decoded-event diagnostics.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalDecodedEventDiagnosticSummaryRow {
    pub(crate) protocol_name: std::string::String,
    pub(crate) event_kind: std::string::String,
    pub(crate) event_category: std::option::Option<std::string::String>,
    pub(crate) trade_candidate: std::option::Option<i64>,
    pub(crate) candle_candidate: std::option::Option<i64>,
    pub(crate) event_count: i64,
    pub(crate) trade_event_count: i64,
}

/// Sample of a decoded trade candidate without linked trade event.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalMissingTradeEventDiagnosticSampleDto {
    /// Decoded event id.
    pub decoded_event_id: i64,
    /// Chain transaction id.
    pub transaction_id: std::option::Option<i64>,
    /// Transaction signature.
    pub signature: std::option::Option<std::string::String>,
    /// Protocol name.
    pub protocol_name: std::string::String,
    /// Event kind.
    pub event_kind: std::string::String,
    /// Pool account.
    pub pool_account: std::option::Option<std::string::String>,
    /// Whether the source transaction failed.
    pub transaction_failed: bool,
    /// Whether this missing trade event is actionable for validation.
    ///
    /// A missing trade event is actionable only when the source transaction
    /// succeeded, the decoded event has a pool account and both token mints,
    /// and the pool is already attached to a known pair. Failed transactions
    /// and incomplete decoded hints remain visible as samples, but they should
    /// not block the non-regression profile.
    pub actionable: bool,
    /// Diagnostic reason explaining why no trade event was linked.
    pub reason: std::string::String,
    /// Whether payload has an explicit base amount.
    pub has_base_amount_payload: bool,
    /// Whether payload has an explicit quote amount.
    pub has_quote_amount_payload: bool,
    /// Whether payload has an explicit price.
    pub has_price_payload: bool,
}

/// Sample of duplicated trade rows grouped by decoded event id.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalDuplicateDecodedEventTradeDiagnosticSampleDto {
    /// Decoded event id.
    pub decoded_event_id: i64,
    /// Protocol name.
    pub protocol_name: std::option::Option<std::string::String>,
    /// Event kind.
    pub event_kind: std::option::Option<std::string::String>,
    /// Pool account.
    pub pool_account: std::option::Option<std::string::String>,
    /// Duplicate trade row count.
    pub trade_event_count: i64,
    /// Trade event ids.
    pub trade_event_ids: std::option::Option<std::string::String>,
    /// Signatures.
    pub signatures: std::option::Option<std::string::String>,
}

/// Sample of multi-trade groups sharing the same signature and pair id.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalMultiTradeSignaturePairDiagnosticSampleDto {
    /// Transaction signature.
    pub signature: std::string::String,
    /// Pair id.
    pub pair_id: i64,
    /// Pool address.
    pub pool_address: std::option::Option<std::string::String>,
    /// DEX code.
    pub dex_code: std::option::Option<std::string::String>,
    /// Trade event count.
    pub trade_event_count: i64,
    /// Distinct decoded event count.
    pub decoded_event_count: i64,
    /// Trade event ids.
    pub trade_event_ids: std::option::Option<std::string::String>,
    /// Decoded event ids.
    pub decoded_event_ids: std::option::Option<std::string::String>,
}

/// Sample of a pair gap.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocalPairGapDiagnosticSampleDto {
    /// Pair id.
    pub pair_id: i64,
    /// Pool address.
    pub pool_address: std::string::String,
    /// DEX code.
    pub dex_code: std::string::String,
    /// Base mint.
    pub base_mint: std::string::String,
    /// Base symbol.
    pub base_symbol: std::option::Option<std::string::String>,
    /// Quote mint.
    pub quote_mint: std::string::String,
    /// Quote symbol.
    pub quote_symbol: std::option::Option<std::string::String>,
    /// Pair symbol.
    pub pair_symbol: std::option::Option<std::string::String>,
    /// Decoded event count.
    pub decoded_event_count: i64,
    /// Decoded trade candidate count.
    pub decoded_trade_candidate_count: i64,
    /// Trade event count.
    pub trade_event_count: i64,
    /// Pair candle count.
    pub pair_candle_count: i64,
}

/// SQL row for missing trade event reason summaries.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalMissingTradeEventReasonSummaryRow {
    pub(crate) reason: std::string::String,
    pub(crate) transaction_failed: i64,
    pub(crate) actionable: i64,
    pub(crate) event_count: i64,
    pub(crate) has_base_amount_payload_count: i64,
    pub(crate) has_quote_amount_payload_count: i64,
    pub(crate) has_price_payload_count: i64,
}

/// SQL row for non-actionable pair diagnostic summaries.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalNonActionablePairDiagnosticSummaryRow {
    pub(crate) pair_id: i64,
    pub(crate) pool_address: std::string::String,
    pub(crate) dex_code: std::string::String,
    pub(crate) base_mint: std::string::String,
    pub(crate) base_symbol: std::option::Option<std::string::String>,
    pub(crate) quote_mint: std::string::String,
    pub(crate) quote_symbol: std::option::Option<std::string::String>,
    pub(crate) pair_symbol: std::option::Option<std::string::String>,
    pub(crate) decoded_trade_candidate_count: i64,
    pub(crate) non_actionable_missing_trade_event_count: i64,
    pub(crate) failed_transaction_candidate_count: i64,
    pub(crate) ok_transaction_without_token_mints_count: i64,
    pub(crate) ok_transaction_without_amount_payload_count: i64,
    pub(crate) reason_summary: std::option::Option<std::string::String>,
    pub(crate) trade_event_count: i64,
    pub(crate) pair_candle_count: i64,
}

/// SQL row for missing trade event samples.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalMissingTradeEventDiagnosticSampleRow {
    pub(crate) decoded_event_id: i64,
    pub(crate) transaction_id: std::option::Option<i64>,
    pub(crate) signature: std::option::Option<std::string::String>,
    pub(crate) protocol_name: std::string::String,
    pub(crate) event_kind: std::string::String,
    pub(crate) pool_account: std::option::Option<std::string::String>,
    pub(crate) transaction_failed: i64,
    pub(crate) actionable: i64,
    pub(crate) reason: std::string::String,
    pub(crate) has_base_amount_payload: i64,
    pub(crate) has_quote_amount_payload: i64,
    pub(crate) has_price_payload: i64,
}

/// SQL row for duplicated decoded event trade samples.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalDuplicateDecodedEventTradeDiagnosticSampleRow {
    pub(crate) decoded_event_id: i64,
    pub(crate) protocol_name: std::option::Option<std::string::String>,
    pub(crate) event_kind: std::option::Option<std::string::String>,
    pub(crate) pool_account: std::option::Option<std::string::String>,
    pub(crate) trade_event_count: i64,
    pub(crate) trade_event_ids: std::option::Option<std::string::String>,
    pub(crate) signatures: std::option::Option<std::string::String>,
}

/// SQL row for multi-trade signature/pair samples.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalMultiTradeSignaturePairDiagnosticSampleRow {
    pub(crate) signature: std::string::String,
    pub(crate) pair_id: i64,
    pub(crate) pool_address: std::option::Option<std::string::String>,
    pub(crate) dex_code: std::option::Option<std::string::String>,
    pub(crate) trade_event_count: i64,
    pub(crate) decoded_event_count: i64,
    pub(crate) trade_event_ids: std::option::Option<std::string::String>,
    pub(crate) decoded_event_ids: std::option::Option<std::string::String>,
}

/// SQL row for pair gap samples.
#[derive(Debug, Clone, sqlx::FromRow)]
pub(crate) struct LocalPairGapDiagnosticSampleRow {
    pub(crate) pair_id: i64,
    pub(crate) pool_address: std::string::String,
    pub(crate) dex_code: std::string::String,
    pub(crate) base_mint: std::string::String,
    pub(crate) base_symbol: std::option::Option<std::string::String>,
    pub(crate) quote_mint: std::string::String,
    pub(crate) quote_symbol: std::option::Option<std::string::String>,
    pub(crate) pair_symbol: std::option::Option<std::string::String>,
    pub(crate) decoded_event_count: i64,
    pub(crate) decoded_trade_candidate_count: i64,
    pub(crate) trade_event_count: i64,
    pub(crate) pair_candle_count: i64,
}
