import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/message.dart';
import 'package:im_app/domain/repositories/message_repository.dart';
import 'package:storage_sdk/storage_sdk.dart';

class MessageRepositoryImpl implements MessageRepository {
  final StorageSdkApi _storage;

  MessageRepositoryImpl(this._storage);

  // ── DB row → Domain ──────────────────────────────────────────────────────

  Message _toEntity(DriftMessage row) => Message(
    id: row.id,
    messageId: row.messageId,
    chatId: row.chatId,
    chatIdx: row.chatIdx,
    sendId: row.sendId,
    content: row.content,
    typ: row.typ,
    sendTime: row.sendTime,
    expireTime: row.expireTime,
    createTime: row.createTime,
    atUsers: row.atUsers,
    emojis: row.emojis,
    editTime: row.editTime,
    refTyp: row.refTyp,
    flag: row.flag,
    cmid: row.cmid,
  );

  // ── Domain → DB companion (internal only) ────────────────────────────────

  MessagesCompanion _toCompanion(Message message) => MessagesCompanion(
    id: Value(message.id),
    messageId: Value(message.messageId),
    chatId: Value(message.chatId),
    chatIdx: Value(message.chatIdx),
    sendId: Value(message.sendId),
    content: Value(message.content),
    typ: Value(message.typ),
    sendTime: Value(message.sendTime),
    expireTime: Value(message.expireTime),
    createTime: Value(message.createTime),
    atUsers: Value(message.atUsers),
    emojis: Value(message.emojis),
    editTime: Value(message.editTime),
    refTyp: Value(message.refTyp),
    flag: Value(message.flag),
    cmid: Value(message.cmid),
  );

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

  @override
  Stream<List<Message>> watchByChatId(int chatId) {
    return _storage
        .watchWhere<DriftMessage, $MessagesTable>(
          (t) => t.chatId.equals(chatId),
        )
        .map((rows) => rows.map(_toEntity).toList());
  }

  @override
  Stream<Message?> watchById(int id) {
    return _storage
        .watchFirst<DriftMessage, $MessagesTable>((t) => t.id.equals(id))
        .map((row) => row != null ? _toEntity(row) : null);
  }

  // ── 读取 ─────────────────────────────────────────────────────────────────

  @override
  Future<List<Message>> getByChatId(int chatId) async {
    final rows = await _storage.rawQuery(
      'SELECT * FROM message WHERE chat_id = ? ORDER BY chat_idx ASC',
      [chatId],
    );
    return rows
        .map(
          (row) => Message(
            id: row.read<int>('id'),
            messageId: row.readNullable<int>('message_id'),
            chatId: row.readNullable<int>('chat_id'),
            chatIdx: row.readNullable<int>('chat_idx'),
            sendId: row.readNullable<int>('send_id'),
            content: row.readNullable<String>('content'),
            typ: row.readNullable<int>('typ'),
            sendTime: row.readNullable<int>('send_time'),
            expireTime: row.readNullable<int>('expire_time'),
            createTime: row.readNullable<int>('create_time'),
            atUsers: row.readNullable<String>('at_users'),
            emojis: row.read<String>('emojis'),
            editTime: row.read<int>('edit_time'),
            refTyp: row.read<int>('ref_typ'),
            flag: row.read<int>('flag'),
            cmid: row.read<String>('cmid'),
          ),
        )
        .toList();
  }

  @override
  Future<List<Message>> getByChatIdPage({
    required int chatId,
    required int offset,
    required int limit,
  }) async {
    final rows = await _storage.rawQuery(
      'SELECT * FROM message WHERE chat_id = ? ORDER BY chat_idx ASC LIMIT ? OFFSET ?',
      [chatId, limit, offset],
    );
    return rows
        .map(
          (row) => Message(
            id: row.read<int>('id'),
            messageId: row.readNullable<int>('message_id'),
            chatId: row.readNullable<int>('chat_id'),
            chatIdx: row.readNullable<int>('chat_idx'),
            sendId: row.readNullable<int>('send_id'),
            content: row.readNullable<String>('content'),
            typ: row.readNullable<int>('typ'),
            sendTime: row.readNullable<int>('send_time'),
            expireTime: row.readNullable<int>('expire_time'),
            createTime: row.readNullable<int>('create_time'),
            atUsers: row.readNullable<String>('at_users'),
            emojis: row.read<String>('emojis'),
            editTime: row.read<int>('edit_time'),
            refTyp: row.read<int>('ref_typ'),
            flag: row.read<int>('flag'),
            cmid: row.read<String>('cmid'),
          ),
        )
        .toList();
  }

  @override
  Future<Message?> getById(int id) async {
    final row = await _storage.selectFirst<DriftMessage, $MessagesTable>(
      (t) => t.id.equals(id),
    );
    return row != null ? _toEntity(row) : null;
  }

  @override
  Future<Message?> getByMessageId(int messageId) async {
    final row = await _storage.selectFirst<DriftMessage, $MessagesTable>(
      (t) => t.messageId.equals(messageId),
    );
    return row != null ? _toEntity(row) : null;
  }

  @override
  Future<int> countByChatId(int chatId) async {
    return _storage.count<DriftMessage, $MessagesTable>(
      filter: (t) => t.chatId.equals(chatId),
    );
  }

  // ── 写入 ─────────────────────────────────────────────────────────────────

  @override
  Future<void> insertOrReplace(Message message) async {
    await _storage.insertOrReplace<DriftMessage>(_toCompanion(message));
  }

  @override
  Future<void> insertOrReplaceAll(List<Message> messages) async {
    await _storage.batchInsertOrReplace<DriftMessage>(
      messages.map(_toCompanion).toList(),
    );
  }

  @override
  Future<void> update(Message message) async {
    await _storage.updateWhere<DriftMessage, $MessagesTable>(
      _toCompanion(message),
      (t) => t.id.equals(message.id),
    );
  }

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

  @override
  Future<void> delete(int id) async {
    await _storage.deleteWhere<DriftMessage, $MessagesTable>(
      (t) => t.id.equals(id),
    );
  }

  @override
  Future<void> deleteByChatId(int chatId) async {
    await _storage.deleteWhere<DriftMessage, $MessagesTable>(
      (t) => t.chatId.equals(chatId),
    );
  }

  @override
  Future<void> clear() async {
    await _storage.deleteAll<DriftMessage>();
  }
}
