/**
 * Stream Renderer 抽象（C-2）— 把 bridge-manager 的 4 套平台流式渲染
 * （飞书 CardKit / 钉钉 AI Card / 企微 replyStream / 默认 edit-draft）
 * 统一成接口，由各 adapter 通过 createStreamRenderer(ctx) 提供。
 *
 * bridge 的 callbacks 退化为薄包装（仅保留 emitImEvent 等 IM 编排），
 * 不再有平台 if-else。每个 renderer 持有自己的状态（StreamingState 退役）。
 */

import type { ToolUseStartInfo, ToolUseEndInfo, DingTalkCardInstance } from '../types'
import type { ChannelAdapter } from './base'
import type { DeliveryLayer } from '../core/delivery'

/** Bridge 传给 renderer 的上下文（一次对话回合一份）。 */
export interface StreamRenderContext {
  adapter: ChannelAdapter
  chatId: string
  channelId: string
  delivery: DeliveryLayer
  /** 钉钉 queue-busy 预建的卡（仅 DingTalkStreamRenderer 用），其余平台 undefined。 */
  preCreatedCard?: DingTalkCardInstance
  /**
   * 默认文本最终投递（EditDraftRenderer.onFinal 的 else 分支用）。
   * 等价原 bridge.deliverPlatformFinal(channelId, chatId, text)。
   */
  deliverPlatformFinal: (text: string) => Promise<void>
}

export interface StreamRenderer {
  /** 对应原 onTyping（bridge 仍先 emitImEvent 再调此）。 */
  onTyping(): Promise<void>
  onReasoning?(text: string): Promise<void>
  onToolUseStart?(tool: ToolUseStartInfo): Promise<void>
  onToolUseEnd?(tool: ToolUseEndInfo): Promise<void>
  onDraft(partialText: string): Promise<void>
  onFinal(text: string): Promise<void>
  /** 异常/超时/abort 清理，等价原 catch 中的渲染清理。 */
  abort(reason: 'abort' | 'error', errorMsg: string): Promise<void>
  /** finally 清理（destroy controller / cleanup frame 等）。 */
  destroy?(): void
  /** bridge 结尾 No-response 检查用：本回合是否已投递任何内容。 */
  readonly delivered: boolean
}

/**
 * 草稿节流/去重工具（从 StreamingState 迁入，逻辑逐行等价）。
 * 用于 DingTalkStreamRenderer / WecomStreamRenderer 的 onDraft。
 * 注意：EditDraftRenderer 只用 isUnchanged，不用 shouldThrottle（默认 edit-draft 无 throttle）。
 */
export class DraftThrottle {
  private lastTime = 0
  private lastText = ''
  constructor(private readonly intervalMs = 800) {}

  /** 镜像 StreamingState.shouldThrottleDraft：间隔内返回 true（不更新时间）；否则更新并返回 false。 */
  shouldThrottle(): boolean {
    const now = Date.now()
    if (now - this.lastTime < this.intervalMs) return true
    this.lastTime = now
    return false
  }

  /** 镜像 StreamingState.isDraftUnchanged：文本相同返回 true；否则更新并返回 false。 */
  isUnchanged(text: string): boolean {
    if (text === this.lastText) return true
    this.lastText = text
    return false
  }
}
