//! Tests for Sealed<String> sqlx integration.

use mad_hatter::Sealed;
use sqlx::SqlitePool;

#[derive(Debug, sqlx::FromRow)]
struct SealedRow {
    id: i32,
    name: Sealed<String>,
}

async fn setup_pool() -> SqlitePool {
    let pool = SqlitePool::connect("sqlite::memory:").await.unwrap();
    sqlx::query("CREATE TABLE test_sealed (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
        .execute(&pool)
        .await
        .unwrap();
    pool
}

#[tokio::test]
async fn test_sealed_string_insert_and_query() {
    let pool = setup_pool().await;
    let sealed_name = Sealed::new("hello world".to_string());

    sqlx::query("INSERT INTO test_sealed (id, name) VALUES (?, ?)")
        .bind(1)
        .bind(&sealed_name)
        .execute(&pool)
        .await
        .unwrap();

    let result: (i32, String) = sqlx::query_as("SELECT id, name FROM test_sealed")
        .fetch_one(&pool)
        .await
        .unwrap();

    assert_eq!(result.0, 1);
    assert_eq!(result.1, "hello world");
}

#[tokio::test]
async fn test_sealed_string_update() {
    let pool = setup_pool().await;

    sqlx::query("INSERT INTO test_sealed (id, name) VALUES (?, ?)")
        .bind(1)
        .bind("original")
        .execute(&pool)
        .await
        .unwrap();

    let sealed_new = Sealed::new("updated value".to_string());
    sqlx::query("UPDATE test_sealed SET name = ? WHERE id = ?")
        .bind(&sealed_new)
        .bind(1)
        .execute(&pool)
        .await
        .unwrap();

    let result: (i32, String) = sqlx::query_as("SELECT id, name FROM test_sealed")
        .fetch_one(&pool)
        .await
        .unwrap();

    assert_eq!(result.1, "updated value");
}

#[tokio::test]
async fn test_sealed_string_unicode() {
    let pool = setup_pool().await;
    let sealed_name = Sealed::new("你好世界 🌍".to_string());

    sqlx::query("INSERT INTO test_sealed (id, name) VALUES (?, ?)")
        .bind(1)
        .bind(&sealed_name)
        .execute(&pool)
        .await
        .unwrap();

    let result: (i32, String) = sqlx::query_as("SELECT id, name FROM test_sealed")
        .fetch_one(&pool)
        .await
        .unwrap();

    assert_eq!(result.1, "你好世界 🌍");
}

#[tokio::test]
async fn test_sealed_string_empty() {
    let pool = setup_pool().await;
    let sealed_name = Sealed::new(String::new());

    sqlx::query("INSERT INTO test_sealed (id, name) VALUES (?, ?)")
        .bind(1)
        .bind(&sealed_name)
        .execute(&pool)
        .await
        .unwrap();

    let result: (i32, String) = sqlx::query_as("SELECT id, name FROM test_sealed")
        .fetch_one(&pool)
        .await
        .unwrap();

    assert_eq!(result.1, "");
}

#[tokio::test]
async fn test_sealed_string_roundtrip() {
    let pool = setup_pool().await;
    let sealed_name = Sealed::new("roundtrip test".to_string());

    sqlx::query("INSERT INTO test_sealed (id, name) VALUES (?, ?)")
        .bind(1)
        .bind(&sealed_name)
        .execute(&pool)
        .await
        .unwrap();

    let row: SealedRow = sqlx::query_as("SELECT id, name FROM test_sealed")
        .fetch_one(&pool)
        .await
        .unwrap();

    assert_eq!(row.id, 1);
    let json = serde_json::to_string(&row.name).unwrap();
    assert_eq!(json, "\"roundtrip test\"");
}

#[tokio::test]
async fn test_sealed_string_roundtrip_unicode() {
    let pool = setup_pool().await;
    let sealed_name = Sealed::new("数据库往返 🔄".to_string());

    sqlx::query("INSERT INTO test_sealed (id, name) VALUES (?, ?)")
        .bind(1)
        .bind(&sealed_name)
        .execute(&pool)
        .await
        .unwrap();

    let row: SealedRow = sqlx::query_as("SELECT id, name FROM test_sealed")
        .fetch_one(&pool)
        .await
        .unwrap();

    let json = serde_json::to_string(&row.name).unwrap();
    assert_eq!(json, "\"数据库往返 🔄\"");
}

// ── Serde tests (no DB) ──

#[test]
fn test_sealed_serde_roundtrip() {
    let original = Sealed::new("serde roundtrip".to_string());
    let json = serde_json::to_string(&original).unwrap();
    assert_eq!(json, "\"serde roundtrip\"");

    let deserialized: Sealed<String> = serde_json::from_str(&json).unwrap();
    let json2 = serde_json::to_string(&deserialized).unwrap();
    assert_eq!(json, json2);
}

#[test]
fn test_sealed_deserialize_from_json_string() {
    let deserialized: Sealed<String> = serde_json::from_str("\"hello world\"").unwrap();
    let json = serde_json::to_string(&deserialized).unwrap();
    assert_eq!(json, "\"hello world\"");
}

#[test]
fn test_sealed_serde_in_struct() {
    #[derive(serde::Serialize, serde::Deserialize)]
    struct MyStruct {
        id: i32,
        name: Sealed<String>,
    }

    let original = MyStruct {
        id: 42,
        name: Sealed::new("structured".to_string()),
    };

    let json = serde_json::to_string(&original).unwrap();
    assert!(json.contains("\"name\":\"structured\""));

    let deserialized: MyStruct = serde_json::from_str(&json).unwrap();
    let json2 = serde_json::to_string(&deserialized).unwrap();
    assert_eq!(json, json2);
}

#[test]
fn test_sealed_deserialize_unicode() {
    let deserialized: Sealed<String> = serde_json::from_str("\"你好世界\"").unwrap();
    let json = serde_json::to_string(&deserialized).unwrap();
    assert_eq!(json, "\"你好世界\"");
}