use erp_plugin::dynamic_table::DynamicTableManager;
use erp_plugin::manifest::{
    PluginEntity, PluginField, PluginFieldType, PluginManifest, PluginMetadata, PluginSchema,
};
use sea_orm::{ConnectionTrait, FromQueryResult};

use super::test_db::TestDb;

/// 构造一个最小默认值的 PluginField（外部 crate 无法使用 #[cfg(test)] 的 default_for_field）
fn make_field(name: &str, field_type: PluginFieldType) -> PluginField {
    PluginField {
        name: name.to_string(),
        field_type,
        required: false,
        unique: false,
        default: None,
        display_name: None,
        ui_widget: None,
        options: None,
        searchable: None,
        filterable: None,
        sortable: None,
        visible_when: None,
        ref_entity: None,
        ref_label_field: None,
        ref_search_fields: None,
        cascade_from: None,
        cascade_filter: None,
        validation: None,
        no_cycle: None,
        scope_role: None,
        ref_plugin: None,
        ref_fallback_label: None,
    }
}

/// 构建测试用 manifest
fn make_test_manifest() -> PluginManifest {
    PluginManifest {
        metadata: PluginMetadata {
            id: "erp-test".to_string(),
            name: "测试插件".to_string(),
            version: "0.1.0".to_string(),
            description: "集成测试用".to_string(),
            author: "test".to_string(),
            min_platform_version: None,
            dependencies: vec![],
        },
        schema: Some(PluginSchema {
            entities: vec![PluginEntity {
                name: "item".to_string(),
                display_name: "测试项".to_string(),
                is_public: None,
                fields: vec![
                    PluginField {
                        name: "code".to_string(),
                        field_type: PluginFieldType::String,
                        required: true,
                        unique: true,
                        display_name: Some("编码".to_string()),
                        searchable: Some(true),
                        ..make_field("code", PluginFieldType::String)
                    },
                    PluginField {
                        name: "name".to_string(),
                        field_type: PluginFieldType::String,
                        required: true,
                        display_name: Some("名称".to_string()),
                        searchable: Some(true),
                        ..make_field("name", PluginFieldType::String)
                    },
                    PluginField {
                        name: "status".to_string(),
                        field_type: PluginFieldType::String,
                        filterable: Some(true),
                        display_name: Some("状态".to_string()),
                        ..make_field("status", PluginFieldType::String)
                    },
                    PluginField {
                        name: "sort_order".to_string(),
                        field_type: PluginFieldType::Integer,
                        sortable: Some(true),
                        display_name: Some("排序".to_string()),
                        ..make_field("sort_order", PluginFieldType::Integer)
                    },
                ],
                indexes: vec![],
                relations: vec![],
                data_scope: None,
                importable: None,
                exportable: None,
            }],
        }),
        events: None,
        ui: None,
        permissions: None,
        settings: None,
        numbering: None,
        templates: None,
        trigger_events: None,
    }
}

#[tokio::test]
async fn test_dynamic_table_create_and_query() {
    let test_db = TestDb::new().await;
    let db = test_db.db();

    let manifest = make_test_manifest();
    let entity = &manifest.schema.as_ref().unwrap().entities[0];

    // 创建动态表
    DynamicTableManager::create_table(db, "erp_test", entity)
        .await
        .expect("创建动态表失败");

    let table_name = DynamicTableManager::table_name("erp_test", &entity.name);

    // 验证表存在
    let exists = DynamicTableManager::table_exists(db, &table_name)
        .await
        .expect("检查表存在失败");
    assert!(exists, "动态表应存在");

    // 插入数据
    let tenant_id = uuid::Uuid::new_v4();
    let user_id = uuid::Uuid::new_v4();
    let data = serde_json::json!({
        "code": "ITEM001",
        "name": "测试项目",
        "status": "active",
        "sort_order": 1
    });

    let (sql, values) =
        DynamicTableManager::build_insert_sql(&table_name, tenant_id, user_id, &data);
    db.execute(sea_orm::Statement::from_sql_and_values(
        sea_orm::DatabaseBackend::Postgres,
        sql,
        values,
    ))
    .await
    .expect("插入数据失败");

    // 查询数据
    let (sql, values) = DynamicTableManager::build_query_sql(&table_name, tenant_id, 10, 0);
    #[derive(FromQueryResult)]
    struct Row {
        id: uuid::Uuid,
        data: serde_json::Value,
    }
    let rows = Row::find_by_statement(sea_orm::Statement::from_sql_and_values(
        sea_orm::DatabaseBackend::Postgres,
        sql,
        values,
    ))
    .all(db)
    .await
    .expect("查询数据失败");

    assert_eq!(rows.len(), 1);
    assert_eq!(rows[0].data["code"], "ITEM001");
    assert_eq!(rows[0].data["name"], "测试项目");
}

#[tokio::test]
async fn test_tenant_isolation_in_dynamic_table() {
    let test_db = TestDb::new().await;
    let db = test_db.db();

    let manifest = make_test_manifest();
    let entity = &manifest.schema.as_ref().unwrap().entities[0];

    DynamicTableManager::create_table(db, "erp_test_iso", entity)
        .await
        .expect("创建动态表失败");

    let table_name = DynamicTableManager::table_name("erp_test_iso", &entity.name);

    let tenant_a = uuid::Uuid::new_v4();
    let tenant_b = uuid::Uuid::new_v4();
    let user_id = uuid::Uuid::new_v4();

    // 租户 A 插入数据
    let data_a = serde_json::json!({"code": "A001", "name": "租户A数据", "status": "active", "sort_order": 1});
    let (sql, values) =
        DynamicTableManager::build_insert_sql(&table_name, tenant_a, user_id, &data_a);
    db.execute(sea_orm::Statement::from_sql_and_values(
        sea_orm::DatabaseBackend::Postgres,
        sql,
        values,
    ))
    .await
    .unwrap();

    // 租户 B 查询不应看到租户 A 的数据
    let (sql, values) = DynamicTableManager::build_query_sql(&table_name, tenant_b, 10, 0);
    #[derive(FromQueryResult)]
    struct Row {
        id: uuid::Uuid,
        data: serde_json::Value,
    }
    let rows = Row::find_by_statement(sea_orm::Statement::from_sql_and_values(
        sea_orm::DatabaseBackend::Postgres,
        sql,
        values,
    ))
    .all(db)
    .await
    .unwrap();

    assert!(rows.is_empty(), "租户 B 不应看到租户 A 的数据");
}
