//! Basic Order Flow Smoke Tests
//!
//! Tests to validate core trading functionality including order submission,
//! querying, cancellation, and position management.

use super::common::*;

#[tokio::test]
async fn test_database_order_submission() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Create a test order
        let order_id = uuid::Uuid::new_v4();
        let user_id = "smoke_test_user";
        let symbol = "BTC-USD";
        let order_type = "market";
        let side = "buy";
        let quantity = 1.0;
        let price = None::<f64>;

        // Insert order
        sqlx::query(
            r#"
            INSERT INTO orders (
                id, user_id, symbol, order_type, side, quantity, price,
                status, created_at, updated_at
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
            "#
        )
        .bind(&order_id)
        .bind(user_id)
        .bind(symbol)
        .bind(order_type)
        .bind(side)
        .bind(quantity)
        .bind(price)
        .bind("pending")
        .execute(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        println!("✅ Order submitted to database");
        println!("   Order ID: {}", order_id);
        println!("   Symbol: {}", symbol);
        println!("   Side: {}", side);
        println!("   Quantity: {}", quantity);

        // Cleanup
        sqlx::query("DELETE FROM orders WHERE id = $1")
            .bind(&order_id)
            .execute(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        pool.close().await;
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_database_order_query() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Create a test order
        let order_id = uuid::Uuid::new_v4();
        let user_id = "smoke_test_user";
        let symbol = "ETH-USD";

        sqlx::query(
            r#"
            INSERT INTO orders (
                id, user_id, symbol, order_type, side, quantity,
                status, created_at, updated_at
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
            "#
        )
        .bind(&order_id)
        .bind(user_id)
        .bind(symbol)
        .bind("limit")
        .bind("sell")
        .bind(2.0)
        .bind("pending")
        .execute(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Query order
        let order: (uuid::Uuid, String, String) = sqlx::query_as(
            "SELECT id, user_id, symbol FROM orders WHERE id = $1"
        )
        .bind(&order_id)
        .fetch_one(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert_eq!(order.0, order_id);
        assert_eq!(order.1, user_id);
        assert_eq!(order.2, symbol);

        println!("✅ Order query successful");
        println!("   Order ID: {}", order.0);
        println!("   User ID: {}", order.1);
        println!("   Symbol: {}", order.2);

        // Cleanup
        sqlx::query("DELETE FROM orders WHERE id = $1")
            .bind(&order_id)
            .execute(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        pool.close().await;
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_database_order_cancellation() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Create a test order
        let order_id = uuid::Uuid::new_v4();

        sqlx::query(
            r#"
            INSERT INTO orders (
                id, user_id, symbol, order_type, side, quantity,
                status, created_at, updated_at
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
            "#
        )
        .bind(&order_id)
        .bind("smoke_test_user")
        .bind("BTC-USD")
        .bind("limit")
        .bind("buy")
        .bind(0.5)
        .bind("pending")
        .execute(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Cancel order
        sqlx::query(
            "UPDATE orders SET status = $1, updated_at = NOW() WHERE id = $2"
        )
        .bind("cancelled")
        .bind(&order_id)
        .execute(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Verify cancellation
        let status: (String,) = sqlx::query_as(
            "SELECT status FROM orders WHERE id = $1"
        )
        .bind(&order_id)
        .fetch_one(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert_eq!(status.0, "cancelled");

        println!("✅ Order cancellation successful");
        println!("   Order ID: {}", order_id);
        println!("   Status: {}", status.0);

        // Cleanup
        sqlx::query("DELETE FROM orders WHERE id = $1")
            .bind(&order_id)
            .execute(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        pool.close().await;
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_database_position_management() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        let position_id = uuid::Uuid::new_v4();
        let user_id = "smoke_test_user";
        let symbol = "BTC-USD";
        let quantity = 1.5;
        let entry_price = 50000.0;

        // Create position
        sqlx::query(
            r#"
            INSERT INTO positions (
                id, user_id, symbol, quantity, entry_price, current_price,
                unrealized_pnl, created_at, updated_at
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
            "#
        )
        .bind(&position_id)
        .bind(user_id)
        .bind(symbol)
        .bind(quantity)
        .bind(entry_price)
        .bind(entry_price) // current_price = entry_price initially
        .bind(0.0) // unrealized_pnl = 0 initially
        .execute(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Query position
        let position: (uuid::Uuid, String, f64, f64) = sqlx::query_as(
            "SELECT id, symbol, quantity, entry_price FROM positions WHERE id = $1"
        )
        .bind(&position_id)
        .fetch_one(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert_eq!(position.0, position_id);
        assert_eq!(position.1, symbol);
        assert_eq!(position.2, quantity);
        assert_eq!(position.3, entry_price);

        println!("✅ Position management successful");
        println!("   Position ID: {}", position.0);
        println!("   Symbol: {}", position.1);
        println!("   Quantity: {}", position.2);
        println!("   Entry Price: ${}", position.3);

        // Cleanup
        sqlx::query("DELETE FROM positions WHERE id = $1")
            .bind(&position_id)
            .execute(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        pool.close().await;
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_database_order_history() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        let user_id = "smoke_test_user";

        // Create multiple test orders
        let order_ids: Vec<uuid::Uuid> = (0..3)
            .map(|_| uuid::Uuid::new_v4())
            .collect();

        for order_id in &order_ids {
            sqlx::query(
                r#"
                INSERT INTO orders (
                    id, user_id, symbol, order_type, side, quantity,
                    status, created_at, updated_at
                )
                VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
                "#
            )
            .bind(order_id)
            .bind(user_id)
            .bind("BTC-USD")
            .bind("market")
            .bind("buy")
            .bind(0.1)
            .bind("filled")
            .execute(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
        }

        // Query order history
        let orders: Vec<(uuid::Uuid, String)> = sqlx::query_as(
            "SELECT id, status FROM orders WHERE user_id = $1 ORDER BY created_at DESC LIMIT 10"
        )
        .bind(user_id)
        .fetch_all(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert!(orders.len() >= 3, "Should find at least 3 orders");

        println!("✅ Order history query successful");
        println!("   Found {} orders for user {}", orders.len(), user_id);

        // Cleanup
        for order_id in &order_ids {
            sqlx::query("DELETE FROM orders WHERE id = $1")
                .bind(order_id)
                .execute(&pool)
                .await
                .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
        }

        pool.close().await;
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_complete_order_lifecycle() {
    println!("🔄 Running complete order lifecycle...");

    let mut steps_passed = 0;
    let total_steps = 4;

    if let Ok(pool) = sqlx::PgPool::connect(&database_url()).await {
        let order_id = uuid::Uuid::new_v4();

        // Step 1: Submit order
        if sqlx::query(
            r#"
            INSERT INTO orders (
                id, user_id, symbol, order_type, side, quantity,
                status, created_at, updated_at
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
            "#
        )
        .bind(&order_id)
        .bind("smoke_test_user")
        .bind("BTC-USD")
        .bind("market")
        .bind("buy")
        .bind(1.0)
        .bind("pending")
        .execute(&pool)
        .await
        .is_ok() {
            println!("  ✓ Order submission");
            steps_passed += 1;
        }

        // Step 2: Query order
        if sqlx::query_as::<_, (String,)>(
            "SELECT status FROM orders WHERE id = $1"
        )
        .bind(&order_id)
        .fetch_one(&pool)
        .await
        .is_ok() {
            println!("  ✓ Order query");
            steps_passed += 1;
        }

        // Step 3: Update order
        if sqlx::query(
            "UPDATE orders SET status = $1, updated_at = NOW() WHERE id = $2"
        )
        .bind("filled")
        .bind(&order_id)
        .execute(&pool)
        .await
        .is_ok() {
            println!("  ✓ Order update");
            steps_passed += 1;
        }

        // Step 4: Cancel/cleanup
        if sqlx::query("DELETE FROM orders WHERE id = $1")
            .bind(&order_id)
            .execute(&pool)
            .await
            .is_ok() {
            println!("  ✓ Order cleanup");
            steps_passed += 1;
        }

        pool.close().await;
    } else {
        println!("  ⚠ Database unavailable - skipping order lifecycle test");
        return;
    }

    println!("\n📊 Order Lifecycle Summary:");
    println!("   Steps passed: {}/{}", steps_passed, total_steps);

    assert_eq!(steps_passed, total_steps, "Complete order lifecycle should pass all steps");
    println!("✅ Order lifecycle check complete");
}
