// file: kb_demo_app/src/demo3old.rs

//! Tauri commands for Demo3old local DEX corpus search.
//!
//! Demo3old is intentionally a thin UI-facing wrapper around `kb_lib` local
//! corpus search services. It does not contain DEX decoding or protocol logic.

use tauri::Manager;
use ts_rs::TS;

/// Request payload for a local DEX corpus search.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusSearchRequest.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusSearchRequest {
    /// Optional DEX code or decoded protocol name.
    pub dex_code: std::option::Option<std::string::String>,
    /// Optional Solana program id.
    pub program_id: std::option::Option<std::string::String>,
    /// Optional local pair id.
    #[ts(type = "number | null")]
    pub pair_id: std::option::Option<i64>,
    /// Optional pool account/address.
    pub pool_address: std::option::Option<std::string::String>,
    /// Optional token mint to match as base, quote or decoded mint.
    pub token_mint: std::option::Option<std::string::String>,
    /// Optional transaction signature.
    pub signature: std::option::Option<std::string::String>,
    /// Maximum number of rows to return per sample category.
    pub limit: u32,
}

/// Response payload returned by Demo3old local DEX corpus search.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusSearchPayload.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusSearchPayload {
    /// Open database URL.
    pub database_url: std::string::String,
    /// Pretty JSON representation of the search result.
    pub result_json: std::string::String,
    /// Structured local DEX corpus search result.
    pub result: Demo3oldLocalDexCorpusSearchResult,
}

/// Structured local DEX corpus search result.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusSearchResult.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusSearchResult {
    /// Normalized search request applied by the backend service.
    pub request: Demo3oldLocalDexCorpusSearchRequest,
    /// Aggregate counts for the matching local data.
    pub summary: Demo3oldLocalDexCorpusSearchSummary,
    /// Matching transaction samples.
    pub transaction_samples: std::vec::Vec<Demo3oldLocalDexCorpusTransactionSample>,
    /// Matching pool/pair samples.
    pub pool_pair_samples: std::vec::Vec<Demo3oldLocalDexCorpusPoolPairSample>,
    /// Matching decoded event samples.
    pub decoded_event_samples: std::vec::Vec<Demo3oldLocalDexCorpusDecodedEventSample>,
}

/// Aggregate counts for one local DEX corpus search.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusSearchSummary.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusSearchSummary {
    /// Number of distinct matching transactions.
    #[ts(type = "number")]
    pub transaction_count: i64,
    /// Number of distinct matching instructions.
    #[ts(type = "number")]
    pub instruction_count: i64,
    /// Number of distinct matching decoded DEX events.
    #[ts(type = "number")]
    pub decoded_event_count: i64,
    /// Number of distinct matching pools.
    #[ts(type = "number")]
    pub pool_count: i64,
    /// Number of distinct matching pairs.
    #[ts(type = "number")]
    pub pair_count: i64,
    /// Number of distinct matching trade events.
    #[ts(type = "number")]
    pub trade_event_count: i64,
    /// Number of distinct matching candle rows.
    #[ts(type = "number")]
    pub pair_candle_count: i64,
    /// Number of distinct matching protocol candidate rows.
    #[ts(type = "number")]
    pub protocol_candidate_count: i64,
}

/// Matching transaction sample for corpus discovery.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusTransactionSample.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusTransactionSample {
    /// Transaction id.
    #[ts(type = "number")]
    pub transaction_id: i64,
    /// Transaction signature.
    pub signature: std::string::String,
    /// Optional Solana slot.
    #[ts(type = "number | null")]
    pub slot: std::option::Option<i64>,
    /// Whether the transaction has a non-null error payload.
    pub failed: bool,
    /// Number of persisted instructions for the transaction.
    #[ts(type = "number")]
    pub instruction_count: i64,
    /// Number of persisted decoded DEX events for the transaction.
    #[ts(type = "number")]
    pub decoded_event_count: i64,
    /// Number of persisted trade events for the transaction.
    #[ts(type = "number")]
    pub trade_event_count: i64,
    /// Comma-separated distinct program ids seen in the transaction.
    pub program_ids_csv: std::string::String,
}

/// Matching pool/pair sample for corpus discovery.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusPoolPairSample.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusPoolPairSample {
    /// Optional pool id.
    #[ts(type = "number | null")]
    pub pool_id: std::option::Option<i64>,
    /// Optional pool address.
    pub pool_address: std::option::Option<std::string::String>,
    /// Optional pair id.
    #[ts(type = "number | null")]
    pub pair_id: std::option::Option<i64>,
    /// Optional DEX code.
    pub dex_code: std::option::Option<std::string::String>,
    /// Optional pair symbol.
    pub pair_symbol: std::option::Option<std::string::String>,
    /// Optional base token mint.
    pub base_mint: std::option::Option<std::string::String>,
    /// Optional base token symbol.
    pub base_symbol: std::option::Option<std::string::String>,
    /// Optional quote token mint.
    pub quote_mint: std::option::Option<std::string::String>,
    /// Optional quote token symbol.
    pub quote_symbol: std::option::Option<std::string::String>,
    /// Number of decoded events attached to the pool.
    #[ts(type = "number")]
    pub decoded_event_count: i64,
    /// Number of trade events attached to the pair.
    #[ts(type = "number")]
    pub trade_event_count: i64,
    /// Number of candle rows attached to the pair.
    #[ts(type = "number")]
    pub pair_candle_count: i64,
    /// Latest known founding or activity signature for the pool/pair.
    pub latest_signature: std::option::Option<std::string::String>,
}

/// Matching decoded event sample for corpus discovery.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[ts(
    export,
    export_to = "../frontend/ts/bindings/Demo3oldLocalDexCorpusDecodedEventSample.ts"
)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Demo3oldLocalDexCorpusDecodedEventSample {
    /// Decoded event id.
    #[ts(type = "number")]
    pub decoded_event_id: i64,
    /// Transaction id.
    #[ts(type = "number")]
    pub transaction_id: i64,
    /// Transaction signature.
    pub signature: std::string::String,
    /// Optional Solana slot.
    #[ts(type = "number | null")]
    pub slot: std::option::Option<i64>,
    /// Protocol name stored on the decoded event.
    pub protocol_name: std::string::String,
    /// Program id stored on the decoded event.
    pub program_id: std::string::String,
    /// Event kind.
    pub event_kind: std::string::String,
    /// Optional pool account.
    pub pool_account: std::option::Option<std::string::String>,
    /// Optional token A mint.
    pub token_a_mint: std::option::Option<std::string::String>,
    /// Optional token B mint.
    pub token_b_mint: std::option::Option<std::string::String>,
    /// Decoded event category extracted from payload JSON.
    pub event_category: std::option::Option<std::string::String>,
    /// Decoded event lifecycle kind extracted from payload JSON.
    pub event_lifecycle_kind: std::option::Option<std::string::String>,
    /// Decoded event actionability extracted from payload JSON.
    pub event_actionability: std::option::Option<std::string::String>,
    /// Whether the decoded event is a trade candidate.
    pub trade_candidate: bool,
    /// Whether the decoded event is a candle candidate.
    pub candle_candidate: bool,
}

/// Opens the `Demo3old` local DEX corpus search window.
#[tauri::command]
pub(crate) fn open_demo3old_window(
    app_handle: tauri::AppHandle,
) -> Result<(), std::string::String> {
    let existing_window_option = app_handle.get_webview_window("demo3old");

    let demo_window = match existing_window_option {
        Some(demo_window) => demo_window,
        None => {
            let builder = tauri::WebviewWindowBuilder::new(
                &app_handle,
                "demo3old",
                tauri::WebviewUrl::App("demo3old.html".into()),
            )
            .title("Demo3old Local DEX Corpus")
            .inner_size(1480.0, 920.0)
            .min_inner_size(1100.0, 720.0)
            .center()
            .visible(true)
            .transparent(false)
            .decorations(true);
            let build_result = builder.build();
            match build_result {
                Ok(window) => window,
                Err(error) => {
                    return Err(format!("cannot create demo3old window: {error:?}"));
                },
            }
        },
    };
    let show_result = demo_window.show();
    if let Err(error) = show_result {
        return Err(format!("cannot show demo3old window: {error:?}"));
    }
    let focus_result = demo_window.set_focus();
    if let Err(error) = focus_result {
        return Err(format!("cannot focus demo3old window: {error:?}"));
    }
    Ok(())
}

/// Searches local DEX corpus candidates from the persisted SQLite pipeline.
#[tauri::command]
pub(crate) async fn demo3old_search_local_dex_corpus(
    state: tauri::State<'_, crate::AppState>,
    request: Demo3oldLocalDexCorpusSearchRequest,
) -> Result<Demo3oldLocalDexCorpusSearchPayload, std::string::String> {
    let database = state.database.clone();
    let service = kb_lib::LocalDexCorpusSearchService::new(database.clone());
    let search_result = service.search(to_lib_search_request(&request)).await;
    let lib_result = match search_result {
        Ok(result) => result,
        Err(error) => {
            return Err(format!("local DEX corpus search failed: {}", error));
        },
    };
    let ui_result = from_lib_search_result(lib_result);
    let result_json_result = serde_json::to_string_pretty(&ui_result);
    let result_json = match result_json_result {
        Ok(result_json) => result_json,
        Err(error) => {
            return Err(format!("cannot serialize local DEX corpus search result: {}", error));
        },
    };
    Ok(Demo3oldLocalDexCorpusSearchPayload {
        database_url: database.database_url().to_string(),
        result_json,
        result: ui_result,
    })
}

fn to_lib_search_request(
    request: &Demo3oldLocalDexCorpusSearchRequest,
) -> kb_lib::LocalDexCorpusSearchRequestDto {
    return kb_lib::LocalDexCorpusSearchRequestDto {
        dex_code: normalize_optional_text(request.dex_code.clone()),
        program_id: normalize_optional_text(request.program_id.clone()),
        pair_id: request.pair_id,
        pool_address: normalize_optional_text(request.pool_address.clone()),
        token_mint: normalize_optional_text(request.token_mint.clone()),
        signature: normalize_optional_text(request.signature.clone()),
        limit: request.limit,
    };
}

fn normalize_optional_text(
    value: std::option::Option<std::string::String>,
) -> std::option::Option<std::string::String> {
    let value = match value {
        Some(value) => value.trim().to_string(),
        None => return None,
    };
    if value.is_empty() {
        return None;
    }
    return Some(value);
}

fn from_lib_search_result(
    result: kb_lib::LocalDexCorpusSearchResultDto,
) -> Demo3oldLocalDexCorpusSearchResult {
    let mut transaction_samples = std::vec::Vec::new();
    for sample in result.transaction_samples {
        transaction_samples.push(from_lib_transaction_sample(sample));
    }
    let mut pool_pair_samples = std::vec::Vec::new();
    for sample in result.pool_pair_samples {
        pool_pair_samples.push(from_lib_pool_pair_sample(sample));
    }
    let mut decoded_event_samples = std::vec::Vec::new();
    for sample in result.decoded_event_samples {
        decoded_event_samples.push(from_lib_decoded_event_sample(sample));
    }
    return Demo3oldLocalDexCorpusSearchResult {
        request: from_lib_request(result.request),
        summary: from_lib_summary(result.summary),
        transaction_samples,
        pool_pair_samples,
        decoded_event_samples,
    };
}

fn from_lib_request(
    request: kb_lib::LocalDexCorpusSearchRequestDto,
) -> Demo3oldLocalDexCorpusSearchRequest {
    return Demo3oldLocalDexCorpusSearchRequest {
        dex_code: request.dex_code,
        program_id: request.program_id,
        pair_id: request.pair_id,
        pool_address: request.pool_address,
        token_mint: request.token_mint,
        signature: request.signature,
        limit: request.limit,
    };
}

fn from_lib_summary(
    summary: kb_lib::LocalDexCorpusSearchSummaryDto,
) -> Demo3oldLocalDexCorpusSearchSummary {
    return Demo3oldLocalDexCorpusSearchSummary {
        transaction_count: summary.transaction_count,
        instruction_count: summary.instruction_count,
        decoded_event_count: summary.decoded_event_count,
        pool_count: summary.pool_count,
        pair_count: summary.pair_count,
        trade_event_count: summary.trade_event_count,
        pair_candle_count: summary.pair_candle_count,
        protocol_candidate_count: summary.protocol_candidate_count,
    };
}

fn from_lib_transaction_sample(
    sample: kb_lib::LocalDexCorpusTransactionSampleDto,
) -> Demo3oldLocalDexCorpusTransactionSample {
    return Demo3oldLocalDexCorpusTransactionSample {
        transaction_id: sample.transaction_id,
        signature: sample.signature,
        slot: sample.slot,
        failed: sample.failed,
        instruction_count: sample.instruction_count,
        decoded_event_count: sample.decoded_event_count,
        trade_event_count: sample.trade_event_count,
        program_ids_csv: sample.program_ids_csv,
    };
}

fn from_lib_pool_pair_sample(
    sample: kb_lib::LocalDexCorpusPoolPairSampleDto,
) -> Demo3oldLocalDexCorpusPoolPairSample {
    return Demo3oldLocalDexCorpusPoolPairSample {
        pool_id: sample.pool_id,
        pool_address: sample.pool_address,
        pair_id: sample.pair_id,
        dex_code: sample.dex_code,
        pair_symbol: sample.pair_symbol,
        base_mint: sample.base_mint,
        base_symbol: sample.base_symbol,
        quote_mint: sample.quote_mint,
        quote_symbol: sample.quote_symbol,
        decoded_event_count: sample.decoded_event_count,
        trade_event_count: sample.trade_event_count,
        pair_candle_count: sample.pair_candle_count,
        latest_signature: sample.latest_signature,
    };
}

fn from_lib_decoded_event_sample(
    sample: kb_lib::LocalDexCorpusDecodedEventSampleDto,
) -> Demo3oldLocalDexCorpusDecodedEventSample {
    return Demo3oldLocalDexCorpusDecodedEventSample {
        decoded_event_id: sample.decoded_event_id,
        transaction_id: sample.transaction_id,
        signature: sample.signature,
        slot: sample.slot,
        protocol_name: sample.protocol_name,
        program_id: sample.program_id,
        event_kind: sample.event_kind,
        pool_account: sample.pool_account,
        token_a_mint: sample.token_a_mint,
        token_b_mint: sample.token_b_mint,
        event_category: sample.event_category,
        event_lifecycle_kind: sample.event_lifecycle_kind,
        event_actionability: sample.event_actionability,
        trade_candidate: sample.trade_candidate,
        candle_candidate: sample.candle_candidate,
    };
}
