import crypto from 'crypto'
import { getDb } from '../client'
import { channelAuditLogs, channelOutboundRefs, channelDedupe } from '../schema'
import { eq, and, desc, sql } from 'drizzle-orm'

/**
 * Channel Audit / Outbound Refs / Dedupe Repository。
 *
 * 封装 channel-misc.ts 中三张附属表的所有查询：
 * - channel_audit_logs：投递审计日志（按时间倒序）
 * - channel_outbound_refs：平台消息 ID 映射（用于后续编辑/撤回）
 * - channel_dedupe：消息去重哈希（TTL 5 分钟）
 *
 * 三表均以 channel_type + chat_id 为业务键（非 channel_id），不参与
 * imChannelRepo.deleteById 的级联——删除 channel 时这些记录按类型保留。
 *
 * 设计约定：
 * - 返回类型由 drizzle 推断，消费方无需 cast
 * - dedupe 用 onConflictDoNothing() 实现 INSERT OR IGNORE 语义
 * - audit/outbound 的 insert 均吞错（原实现用 try/catch + ignore），本 repo 不吞——
 *   消费方按需包裹 try/catch
 */

export const channelAuditRepo = {
  // ────────────────────────────────────────────────────────────
  // Audit logs
  // ────────────────────────────────────────────────────────────

  /** 写入审计日志（details 自动 JSON.stringify） */
  insertAudit(
    channelType: string,
    chatId: string,
    action: string,
    details: unknown,
  ) {
    getDb()
      .insert(channelAuditLogs)
      .values({
        id: crypto.randomUUID(),
        channelType,
        chatId,
        action,
        details: JSON.stringify(details),
      })
      .run()
  },

  /** 按 channel_type + chat_id 查审计日志，按 created_at 倒序，限量 */
  listByChannelChat(
    channelType: string,
    chatId: string,
    limit = 100,
  ) {
    return getDb()
      .select()
      .from(channelAuditLogs)
      .where(
        and(
          eq(channelAuditLogs.channelType, channelType),
          eq(channelAuditLogs.chatId, chatId),
        ),
      )
      .orderBy(desc(channelAuditLogs.createdAt))
      .limit(limit)
      .all()
  },

  /** 全局近期审计日志（管理面板用），按 created_at 倒序 */
  listRecent(limit = 100) {
    return getDb()
      .select()
      .from(channelAuditLogs)
      .orderBy(desc(channelAuditLogs.createdAt))
      .limit(limit)
      .all()
  },

  /** 按 channel_type 清理审计日志（运维用） */
  deleteByChannelType(channelType: string) {
    getDb()
      .delete(channelAuditLogs)
      .where(eq(channelAuditLogs.channelType, channelType))
      .run()
  },

  // ────────────────────────────────────────────────────────────
  // Outbound refs（平台消息 ID 映射）
  // ────────────────────────────────────────────────────────────

  /** 记录一条 outbound ref（投递成功后追踪 platform_msg_id） */
  insertOutboundRef(
    channelType: string,
    chatId: string,
    internalId: string,
    platformMsgId: string,
  ) {
    getDb()
      .insert(channelOutboundRefs)
      .values({
        id: crypto.randomUUID(),
        channelType,
        chatId,
        internalId,
        platformMsgId,
      })
      .run()
  },

  /** 按 channel_type + chat_id + internal_id 查 platform_msg_id（编辑/撤回时反查） */
  findOutboundRef(
    channelType: string,
    chatId: string,
    internalId: string,
  ) {
    return getDb()
      .select({
        id: channelOutboundRefs.id,
        platformMsgId: channelOutboundRefs.platformMsgId,
        createdAt: channelOutboundRefs.createdAt,
      })
      .from(channelOutboundRefs)
      .where(
        and(
          eq(channelOutboundRefs.channelType, channelType),
          eq(channelOutboundRefs.chatId, chatId),
          eq(channelOutboundRefs.internalId, internalId),
        ),
      )
      .get()
  },

  /** 列出 channel_type + chat_id 的全部 outbound ref（管理用） */
  listOutboundRefsByChannelChat(channelType: string, chatId: string) {
    return getDb()
      .select()
      .from(channelOutboundRefs)
      .where(
        and(
          eq(channelOutboundRefs.channelType, channelType),
          eq(channelOutboundRefs.chatId, chatId),
        ),
      )
      .orderBy(desc(channelOutboundRefs.createdAt))
      .all()
  },

  /** 按 id 删除 outbound ref */
  deleteOutboundRefById(id: string) {
    getDb().delete(channelOutboundRefs).where(eq(channelOutboundRefs.id, id)).run()
  },

  /** 按 channel_type + chat_id 删除全部 outbound ref */
  deleteOutboundRefsByChannelChat(channelType: string, chatId: string) {
    getDb()
      .delete(channelOutboundRefs)
      .where(
        and(
          eq(channelOutboundRefs.channelType, channelType),
          eq(channelOutboundRefs.chatId, chatId),
        ),
      )
      .run()
  },

  // ────────────────────────────────────────────────────────────
  // Dedupe（消息去重，TTL 5 分钟）
  // ────────────────────────────────────────────────────────────

  /** 检查 hash 是否已存在（返回 true 表示重复） */
  isDedupeHit(hash: string): boolean {
    const row = getDb()
      .select({ hash: channelDedupe.hash })
      .from(channelDedupe)
      .where(eq(channelDedupe.hash, hash))
      .get()
    return row !== undefined
  },

  /**
   * 插入去重记录（INSERT OR IGNORE 语义，hash 冲突时静默跳过）。
   * 配合 isDedupeHit 实现 check-then-insert 原子去重。
   */
  insertDedupe(hash: string, channelType: string, chatId: string) {
    getDb()
      .insert(channelDedupe)
      .values({ hash, channelType, chatId })
      .onConflictDoNothing()
      .run()
  },

  /** 删除过期去重记录（created_at < now - 5 分钟），由 delivery 层节流调用 */
  deleteExpiredDedupe() {
    getDb()
      .delete(channelDedupe)
      .where(sql`${channelDedupe.createdAt} < datetime('now', '-5 minutes')`)
      .run()
  },

  /** 按 hash 删除单条去重记录 */
  deleteDedupeByHash(hash: string) {
    getDb().delete(channelDedupe).where(eq(channelDedupe.hash, hash)).run()
  },
}
