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

/// 通话记录仓储实现
///
/// ## 职责
/// - 所有 DB 操作通过 [StorageSdkApi]，不直接接触 AppDatabase
/// - DriftCallLog ↔ Domain CallLog 映射
/// - 所有公开接口只接受 Domain 实体，Companion 转换完全内聚在此类
///
/// ## 数据流
/// ```
/// 网络：CallLog.fromJson(json) → insertOrReplaceCallLog(callLog) → StorageSdkApi → DB
/// 监听：StorageSdkApi.watchAll → DriftCallLog → _toEntity() → UI
/// ```
class CallLogRepositoryImpl implements CallLogRepository {
  final StorageSdkApi _storage;

  CallLogRepositoryImpl(this._storage);

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

  CallLog _toEntity(DriftCallLog row) => CallLog(
    id: row.id,
    callerId: row.callerId,
    receiverId: row.receiverId,
    chatId: row.chatId,
    duration: row.duration,
    videoCall: row.videoCall,
    createdAt: row.createdAt,
    updatedAt: row.updatedAt,
    endedAt: row.endedAt,
    status: row.status,
    isDeleted: row.isDeleted,
    deletedAt: row.deletedAt,
    isRead: row.isRead,
  );

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

  CallLogsCompanion _toCompanion(CallLog callLog) => CallLogsCompanion(
    id: Value(callLog.id),
    callerId: Value(callLog.callerId),
    receiverId: Value(callLog.receiverId),
    chatId: Value(callLog.chatId),
    duration: Value(callLog.duration),
    videoCall: Value(callLog.videoCall),
    createdAt: Value(callLog.createdAt),
    updatedAt: Value(callLog.updatedAt),
    endedAt: Value(callLog.endedAt),
    status: Value(callLog.status),
    isDeleted: Value(callLog.isDeleted),
    deletedAt: Value(callLog.deletedAt),
    isRead: Value(callLog.isRead),
  );

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

  @override
  Stream<List<CallLog>> watchAllCallLogs() {
    return _storage.watchAll<DriftCallLog>().map(
      (rows) => rows.map(_toEntity).toList(),
    );
  }

  @override
  Stream<CallLog?> watchCallLog(String id) {
    return _storage
        .watchFirst<DriftCallLog, $CallLogsTable>((t) => t.id.equals(id))
        .map((row) => row != null ? _toEntity(row) : null);
  }

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

  @override
  Future<List<CallLog>> getCallLogs() async {
    final rows = await _storage.rawQuery(
      'SELECT * FROM call_log ORDER BY updated_at DESC',
      [],
    );
    return rows
        .map(
          (row) => CallLog(
            id: row.read<String>('id'),
            callerId: row.readNullable<int>('caller_id'),
            receiverId: row.readNullable<int>('receiver_id'),
            chatId: row.readNullable<int>('chat_id'),
            duration: row.readNullable<int>('duration'),
            videoCall: row.readNullable<int>('video_call'),
            createdAt: row.readNullable<int>('created_at'),
            updatedAt: row.readNullable<int>('updated_at'),
            endedAt: row.readNullable<int>('ended_at'),
            status: row.readNullable<int>('status'),
            isDeleted: row.readNullable<int>('is_deleted'),
            deletedAt: row.readNullable<int>('deleted_at'),
            isRead: row.readNullable<int>('is_read'),
          ),
        )
        .toList();
  }

  @override
  Future<CallLog?> getCallLog(String id) async {
    final row = await _storage.selectFirst<DriftCallLog, $CallLogsTable>(
      (t) => t.id.equals(id),
    );
    return row != null ? _toEntity(row) : null;
  }

  @override
  Future<bool> isExist(String id) async {
    final row = await _storage.selectFirst<DriftCallLog, $CallLogsTable>(
      (t) => t.id.equals(id),
    );
    return row != null;
  }

  @override
  Future<int> getUnreadCount(int currentUid) async {
    final result = await _storage.rawQuery(
      '''
      SELECT COUNT(*) as count FROM call_log
      WHERE is_read = 0
        AND caller_id != ?
        AND (status = 3 OR status = 4 OR status = 5 OR status = 6)
      ''',
      [currentUid],
    );
    if (result.isNotEmpty) {
      return result.first.read<int>('count');
    }
    return 0;
  }

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

  @override
  Future<void> insertOrReplaceCallLog(CallLog callLog) async {
    await _storage.insertOrReplace<DriftCallLog>(_toCompanion(callLog));
  }

  @override
  Future<void> insertOrReplaceCallLogs(List<CallLog> callLogs) async {
    await _storage.batchInsertOrReplace<DriftCallLog>(
      callLogs.map(_toCompanion).toList(),
    );
  }

  @override
  Future<void> markAllAsRead() async {
    await _storage.rawQuery('UPDATE call_log SET is_read = 1', []);
  }

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

  @override
  Future<void> deleteCallLog(String id) async {
    await _storage.deleteWhere<DriftCallLog, $CallLogsTable>(
      (t) => t.id.equals(id),
    );
  }
}
