import type { ReactNode } from 'react'
import type { TSimpleTheme } from './APP'
import type { AppConfig, CautionItem } from './CONFIG'
import INPUTPROPS from './INPUTPROPS'
import type { TopicInfo } from './UI'

export type Position = 'left' | 'right' | 'center'

export type THistoryMsg = [cid: string, msgs: MsgProps[]]
export type THistoryComposer = {
  // text: any  // 输入框文字
  // file: any[]  // 输入框上传文件
  controller?: any // fetch控制器
} & INPUTPROPS

export interface MsgPropsWithoutId {
  type: string
  content: any
  position?: Position
  user?: {
    avatar?: string | Element
    name?: string
  }
  createdAt?: number
  hasTime?: boolean
  feedback?: {
    rating: 'like' | 'dislike' | null
  },
  files?: Array<string>,
  isTyping?: boolean
}

export interface MsgProps extends MsgPropsWithoutId {
  _id: string
}

// 使用映射类型使 MsgPropsWithoutId 的所有属性都变为可选
export type MsgPropsWithoutIdAllOptional = {
  [P in keyof MsgPropsWithoutId]?: MsgPropsWithoutId[P];
};

export type CitationInfo = { snapshoot?: any; _id: string, originData?: any }

export type InputRefFunc = {
  /** 聚焦 */
  focus: () => InputRefFunc
  /** 失焦 */
  blur: () => InputRefFunc
  /** setText: 设置输入框内容
   * @param text 
   * @returns InputRefFunc
   */
  setText: (text: string) => InputRefFunc
  getText: () => string
  /** handleSend: 开始发送
   * @param  
   * @returns InputRefFunc
  */
  handleSend: () => InputRefFunc
  /** 设置输入框引用内容
    * @param info._id 必传参数 消息id（snapshoot值优先级高于_id）
    * @param info.snapshoot 可选参数 展示内容
    * 例如 ctx.chat.inputRef.setCitation({ _id: '123', snapshoot: <>引用内容</> })  展示snapshoot内容
    * 例如 ctx.chat.inputRef.setCitation({ _id: 'zxcvbnm' }) 展示消息的DOM快照
    * @returns InputRefFunc
    */
  setCitation: (info: CitationInfo) => InputRefFunc
  /** 获取输入框引用内容
   * @returns CitationInfo.originData 引用的消息数据本身
   *          CitationInfo._id 引用的消息数据id
   */
  getCitation: () => CitationInfo
  /** 获取指令@发送消息后的应用数据
   * @returns CautionItem.ItemIcon 图标
   * @returns CautionItem.ItemName 名称
   * @returns CautionItem.ItemDesc 描述
   * @returns CautionItem.xx 其他字段
   */
  getConfirmAite: () => CautionItem

  getShowAite: () => boolean,
  setShowAite: (show: boolean) => InputRefFunc
  showAiteList: (show: boolean, resetSearch?: boolean) => InputRefFunc
}

export interface CtxTopic {
  [key: string]: any
  getList: () => Array<TopicInfo>
  find: (_id: string) => TopicInfo | null
  open: (_id: string) => boolean
  del: (_id: string) => void
  /** prepend: 追加消息
   * @param _t id已存在时属于操作失败
   * @returns 操作失败返回null
   */
  prepend: (_t?: TopicInfo) => TopicInfo | null
  /** append: 追加消息
  * @param _t id已存在时属于操作失败
  * @returns 操作失败返回null
  */
  append: (_t?: TopicInfo) => TopicInfo | null
  update: (_t: TopicInfo) => void
  reset: (_arr: Array<TopicInfo>) => void
  /** updateHistoryComposer: 更新控制器，可在自定义流式返回的方法中使用,及时更新控制器,从而不影响停止生成功能
   * @param _cid 话题id
   * @param _obj _obj.controller fetch控制器
   * @returns 
   */
  updateHistoryComposer: (_cid: string, _obj: THistoryComposer) => void,
  /** updateHistoryMsgList: 更新批量消息列表
   * @param _cid 话题id
   * @param _msgs 
   * @returns 
   */
  updateHistoryMsgList: (_cid: string, _msgs: MsgProps[]) => void,
  updateHistoryMsg: (_cid: string, _msg: MsgProps) => void,
}

export interface CurrChatCtx {
  [key: string]: any
  /** getChatMessages: 获取当前对话框中的消息列表
   * @returns Array<MsgProps>
   */
  getChatMessages: () => Array<MsgProps>
  /** appendMsg: 追加消息
   * @param posi 'left' | 'right' | 'center'
   * @param msg type content 必须
   * @returns 
   */
  appendMsg: (posi: Position, msg: MsgProps, scrollToEnd?: boolean) => void
  prependMsg: (posi: Position, msg: MsgProps, scrollToTop?: boolean) => void
  /** updateMsg: 更新消息
   * @param id 
   * @param msg
   * @returns 
   */
  updateMsg: (id: string, msg: MsgPropsWithoutIdAllOptional) => void
  /** deleteMsg: 删除消息
   * @param id 
   * @returns 
   */
  deleteMsg: (id: string) => void
  /** resetList: 重置列表
   * @param list type content 必须
   * @returns 
   */
  resetList: (list: Array<MsgProps & { actions?: boolean | string[]; }>) => void
  /** scrollToEnd: 滚动到底部
   * @param opt 
   * @returns 
   */
  scrollToEnd: (opt?: { delay?: number, force?: boolean, animated?: any }) => void

  // 输入框实例方法
  inputRef: InputRefFunc

  // setTyping: (typing: boolean) => void
  /** breakRequest: 暂停请求,并恢复发送按钮
   * @returns 
   */
  breakRequest: () => void
  /** setInputPattern 修改按钮发送状态 */
  setInputPattern: (pattern: 'send' | 'stop') => void

  /** 设置滚动到顶部的回调onScrollTo触发条件 true=前面还有历史记录 false=前面没有历史记录了 */
  setHistoryHasMoreUp: (_boo: boolean) => void
  /** 设置滚动到底部的回调onScrollTo触发条件 同上*/
  setHistoryHasMoreDown: (_boo: boolean) => void
}

export interface CtxLayout {
  setShowAreaLeft?: (_v: boolean) => void
  setShowAreaRight?: (_v: boolean) => void
  setShowTopHeader?: (_v: boolean) => void
}

export interface CtxSource {
  /** getList 获取当前上传的所有资源 */
  getList: () => Array<any>
  /** clearList 清除当前上传的所有资源 */
  clearList?: () => void
}
export interface TPop_Option {
  open: boolean
  Content?: ReactNode
  shadeClass?: string
  contentClass?: string
  openChange?: (_isopen: boolean) => void
}

export interface CTX {
  /** status: 实例化状态
   * succeed 表示成功 CTX的api都可使用
   * failed 表示失败 CTX的api怎样暂不处理
   * pending 表示正在初始化中 CTX的api怎样暂不处理
   */
  status: 'succeed' | 'failed' | 'pending'
  /** setConfig: 更新 CustomConfig.config 内容
   * 即时生效
   * 需要注意的是
   *  ① robot、user只有在设置后的消息渲染中生效
   * @param config 
   * @param isMerge 是否合并默认为true
   * @returns 
   * ps: 可以用于发送request前更新对应的携带参数值如header、body
   */
  setConfig: (config: AppConfig, isMerge?: boolean) => void
  /** topic: 左侧话题列表实例
   * 包括操作: 打开、删除、前追加、后追加、更新、重置
   */
  topic: CtxTopic
  /** chat: 当前对话实例
   * 包括操作: 追加、更新、删除、重置、滚动到底部、设置文本、设置输入状态
   */
  chat: CurrChatCtx
  /** layout: 布局实例
   * 包括操作: 设置左侧区域显示状态、设置右侧区域显示状态、设置顶部区域显示状态
   */
  layout: CtxLayout
  /** source: 资源实例
   * 包括操作: 获取资源列表、清除资源列表
   */
  source: CtxSource
  /** setTheme: 设置主题色
   * @param _name "LightViolet" | "DarkViolet" | "LightBerry" | "DarkBerry" | "LightWarm" | "DarkWarm"  
   * @returns 
   */
  setTheme: (_name: TSimpleTheme) => void
  /** setBottomPop 设置一个从底部弹出的pop组件，只有移动小屏<768px时显示
   * @param _options 
   * open: boolean 默认打开
   * Content?: ReactNode 容器内容
   * shadeClass?: string 遮罩样式
   * contentClass?: string 容器样式
   * openChange?: (_isopen: boolean) => void pop打开关闭回调
   * @returns 
   */
  setBottomPop: (_options: TPop_Option) => void
}
