use crate::error::DalError;
use crate::models::market_subscription::{
    ActiveSubscriptionRow, EnrichedSubscriptionRow, MarketSubscriptionRow,
};
use sqlx::PgPool;

/// Upsert a market subscription. If it already exists (instrument_id + sub_kind),
/// reactivate it and update the timestamp.
pub async fn upsert(
    pool: &PgPool,
    instrument_id: i32,
    sub_kind: &str,
) -> Result<MarketSubscriptionRow, DalError> {
    let row = sqlx::query_as::<_, MarketSubscriptionRow>(
        "INSERT INTO market_subscriptions (instrument_id, sub_kind)
         VALUES ($1, $2)
         ON CONFLICT (instrument_id, sub_kind)
         DO UPDATE SET active = true, updated_at = now()
         RETURNING id, instrument_id, sub_kind, active, created_at, updated_at",
    )
    .bind(instrument_id)
    .bind(sub_kind)
    .fetch_one(pool)
    .await?;

    Ok(row)
}

/// List all active subscriptions joined with instrument and exchange data.
/// Used by the market-worker to discover what to subscribe to.
pub async fn list_active(pool: &PgPool) -> Result<Vec<ActiveSubscriptionRow>, DalError> {
    let rows = sqlx::query_as::<_, ActiveSubscriptionRow>(
        "SELECT
             ms.id AS subscription_id,
             ms.instrument_id,
             ms.sub_kind,
             e.name AS exchange_name,
             i.name_exchange,
             i.base_asset,
             i.quote_asset,
             i.kind
         FROM market_subscriptions ms
         JOIN instruments i ON i.id = ms.instrument_id
         JOIN exchanges e ON e.id = i.exchange_id
         WHERE ms.active = true
         ORDER BY ms.id",
    )
    .fetch_all(pool)
    .await?;

    Ok(rows)
}

/// List subscriptions enriched with exchange/instrument info, optionally filtered to active-only.
pub async fn list_enriched(
    pool: &PgPool,
    active_only: bool,
) -> Result<Vec<EnrichedSubscriptionRow>, DalError> {
    let base_query = "SELECT
             ms.id,
             ms.instrument_id,
             ms.sub_kind,
             ms.active,
             ms.created_at,
             ms.updated_at,
             e.name AS exchange_name,
             i.base_asset,
             i.quote_asset
         FROM market_subscriptions ms
         JOIN instruments i ON i.id = ms.instrument_id
         JOIN exchanges e ON e.id = i.exchange_id";

    let rows = if active_only {
        sqlx::query_as::<_, EnrichedSubscriptionRow>(
            &format!("{base_query} WHERE ms.active = true ORDER BY ms.id"),
        )
        .fetch_all(pool)
        .await?
    } else {
        sqlx::query_as::<_, EnrichedSubscriptionRow>(
            &format!("{base_query} ORDER BY ms.id"),
        )
        .fetch_all(pool)
        .await?
    };

    Ok(rows)
}

/// List all subscriptions, optionally filtered to active-only.
pub async fn list_all(
    pool: &PgPool,
    active_only: bool,
) -> Result<Vec<MarketSubscriptionRow>, DalError> {
    let rows = if active_only {
        sqlx::query_as::<_, MarketSubscriptionRow>(
            "SELECT id, instrument_id, sub_kind, active, created_at, updated_at
             FROM market_subscriptions
             WHERE active = true
             ORDER BY id",
        )
        .fetch_all(pool)
        .await?
    } else {
        sqlx::query_as::<_, MarketSubscriptionRow>(
            "SELECT id, instrument_id, sub_kind, active, created_at, updated_at
             FROM market_subscriptions
             ORDER BY id",
        )
        .fetch_all(pool)
        .await?
    };

    Ok(rows)
}

/// Soft-delete: deactivate a subscription by setting active=false.
pub async fn deactivate(pool: &PgPool, id: i32) -> Result<Option<MarketSubscriptionRow>, DalError> {
    let row = sqlx::query_as::<_, MarketSubscriptionRow>(
        "UPDATE market_subscriptions
         SET active = false, updated_at = now()
         WHERE id = $1
         RETURNING id, instrument_id, sub_kind, active, created_at, updated_at",
    )
    .bind(id)
    .fetch_optional(pool)
    .await?;

    Ok(row)
}

/// Get a single subscription by ID.
pub async fn get_by_id(pool: &PgPool, id: i32) -> Result<Option<MarketSubscriptionRow>, DalError> {
    let row = sqlx::query_as::<_, MarketSubscriptionRow>(
        "SELECT id, instrument_id, sub_kind, active, created_at, updated_at
         FROM market_subscriptions
         WHERE id = $1",
    )
    .bind(id)
    .fetch_optional(pool)
    .await?;

    Ok(row)
}
