import 'package:drift/drift.dart';

import '../wiring/storage_sdk_wiring.dart';

/// 本地数据库的统一公开接口。
///
/// 通过 [StorageSdkApi] 工厂方法获取实例，传入 App 侧的数据库工厂和表注册表即可：
///
/// ```dart
/// final api = StorageSdkApi(
///   databaseFactory: (executor) => AppDatabase(executor),
///   tableRegistry: (db) => {
///     User: (db as AppDatabase).users,
///   },
/// );
/// ```
///
/// ## 生命周期
/// - 用户登录后调用 [openDatabase] 开库；
/// - 用户登出时调用 [closeDatabase] 关库；
/// - [isDatabaseOpen] 可查询当前状态。
///
/// 内部接口，仅供 App 层生命周期管理使用
abstract class StorageSdkLifecycle {
  /// 打开指定用户的数据库（按 uid 隔离文件）。
  Future<void> openDatabase(int uid);

  /// 关闭当前数据库连接。
  Future<void> closeDatabase();

  /// 是否已开库。
  bool get isDatabaseOpen;
}

/// ## CRUD
/// 所有 CRUD 方法均通过泛型数据类型查找对应表，与具体业务表解耦。
/// App 层通过 [tableRegistry] 注入表映射，无需在调用时传入 [TableInfo]。
abstract class StorageSdkApi {
  /// 创建 SDK 实例。
  ///
  /// [databaseFactory] 由 App 层提供：接受 [QueryExecutor]，
  /// 返回自定义的 [GeneratedDatabase] 子类（含表定义和迁移策略）。
  ///
  /// [tableRegistry] 由 App 层提供：将数据类映射到对应的表信息，
  /// storage_sdk 不感知具体表结构。
  ///
  /// 示例：
  /// ```dart
  /// final api = StorageSdkApi(
  ///   databaseFactory: (executor) => AppDatabase(executor),
  ///   tableRegistry: (db) => {
  ///     User: (db as AppDatabase).users,
  ///   },
  /// );
  /// ```
  factory StorageSdkApi({
    required GeneratedDatabase Function(QueryExecutor) databaseFactory,
    required Map<Type, TableInfo> Function(GeneratedDatabase) tableRegistry,
  }) => StorageSdkWiring.build(
    databaseFactory: databaseFactory,
    tableRegistry: tableRegistry,
  );

  // ── 事务 ─────────────────────────────────────────────────────────────────

  /// 在单个事务内执行 [action]。
  ///
  /// - 成功则自动 COMMIT
  /// - 抛出异常则自动 ROLLBACK，异常会继续向上传递
  ///
  /// 示例：
  /// ```dart
  /// await _storage.transaction(() async {
  ///   await _storage.insertOrReplace(companionA);
  ///   await _storage.updateWhere(companionB, (t) => t.uid.equals(1));
  /// });
  /// ```
  Future<T> transaction<T>(Future<T> Function() action);

  // ── 插入 ─────────────────────────────────────────────────────────────────

  /// 插入或替换（主键冲突时删除原行再插入）。
  ///
  /// 注意：底层是 DELETE + INSERT，会导致 rowid 变更，并触发 DELETE 级联。
  /// 如需原地更新，请使用 [insertOnConflictUpdate]。
  ///
  /// 示例：
  /// ```dart
  /// await sdk.insertOrReplace<UsersCompanion>(
  ///   UsersCompanion.insert(nickname: Value('Edmund')),
  /// );
  /// ```
  Future<void> insertOrReplace<D>(Insertable<D> companion);

  /// 插入或忽略（主键冲突时跳过）。
  Future<void> insert<D>(Insertable<D> companion);

  /// 批量插入或替换（主键冲突时删除原行再插入）。
  ///
  /// 注意：底层是 DELETE + INSERT，rowid 变更，触发 DELETE 级联。
  /// 如需原地更新，请使用 [batchInsertOnConflictUpdate]。
  Future<void> batchInsertOrReplace<D>(List<Insertable<D>> companions);

  /// 插入，主键冲突时原地更新全部字段（INSERT ... ON CONFLICT DO UPDATE SET）。
  ///
  /// 与 [insertOrReplace] 的区别：
  /// - [insertOrReplace]        → DELETE + INSERT，rowid 变更，触发 DELETE 级联
  /// - [insertOnConflictUpdate] → 原地 UPDATE，rowid 不变，不触发 DELETE 级联
  ///
  /// 适用场景：upsert 语义，且不希望影响依赖 rowid 的其他逻辑。
  Future<void> insertOnConflictUpdate<D>(Insertable<D> companion);

  /// 批量插入，主键冲突时原地更新全部字段。
  ///
  /// 与 [batchInsertOrReplace] 的区别同 [insertOnConflictUpdate]。
  Future<void> batchInsertOnConflictUpdate<D>(List<Insertable<D>> companions);

  // ── 更新 ─────────────────────────────────────────────────────────────────

  /// 按条件更新。
  ///
  /// 示例：
  /// ```dart
  /// await sdk.updateWhere<User, $UsersTable>(
  ///   UsersCompanion(nickname: Value('NewName')),
  ///   (t) => t.uid.equals(123),
  /// );
  /// ```
  Future<void> updateWhere<D, T extends Table>(
    Insertable<D> companion,
    Expression<bool> Function(T) filter,
  );

  // ── 删除 ─────────────────────────────────────────────────────────────────

  /// 按条件删除。
  Future<void> deleteWhere<D, T extends Table>(
    Expression<bool> Function(T) filter,
  );

  /// 清空整张表。
  Future<void> deleteAll<D>();

  // ── 查询 ─────────────────────────────────────────────────────────────────

  /// 查询全部记录。
  ///
  /// 示例：
  /// ```dart
  /// final users = await sdk.selectAll<User>();
  /// ```
  Future<List<D>> selectAll<D>();

  /// 按条件查询。
  Future<List<D>> selectWhere<D, T extends Table>(
    Expression<bool> Function(T) filter,
  );

  /// 查询第一条匹配记录。
  Future<D?> selectFirst<D, T extends Table>(
    Expression<bool> Function(T) filter,
  );

  // ── 监听 ─────────────────────────────────────────────────────────────────

  /// 监听全部记录（实时流）。
  Stream<List<D>> watchAll<D>();

  /// 按条件监听（实时流）。
  Stream<List<D>> watchWhere<D, T extends Table>(
    Expression<bool> Function(T) filter,
  );

  /// 监听第一条匹配记录（实时流）。
  Stream<D?> watchFirst<D, T extends Table>(
    Expression<bool> Function(T) filter,
  );

  // ── 原始 SQL ─────────────────────────────────────────────────────────────

  /// 执行原始查询，返回行数据。
  Future<List<QueryRow>> rawQuery(String sql, [List<Object?> args]);

  /// 执行原始语句（无返回值）。
  Future<void> rawExecute(String sql, [List<Object?> args]);

  // ── 统计 ─────────────────────────────────────────────────────────────────

  /// 统计记录数。
  Future<int> count<D, T extends Table>({Expression<bool> Function(T)? filter});
}
