import { AgentChatHistoryItem } from "@/api/agent/Agent";
import type OpenAI from "openai";
import { StringUtils } from "@imengyu/imengyu-utils";
import { AgentChatFile } from "@/api/agent/AgentChatFile";
import type { ChatAttachmentItem } from "../core/Chat";

export type ChatMessageType = 'text' | 'image_url' | 'input_audio' | 'input_file' | 'video' | 'video_url';
export type ChatMessageState = 'loading' | 'success' | 'error';
export type ChatMessageRole = "user" | "assistant" | "system" | "tool";

export class ChatMessage {
  id = 0;
  /**
   * 角色
   */
  role = 'assistant' as ChatMessageRole;
  /**
   * 状态
   */
  state = 'loading' as ChatMessageState;
  /**
   * type string （必选）

    可选值：
    text 输入文本时需设为text。
    image_url 输入图片时需设为image_url。
    input_audio 输入音频时需设为input_audio。
    input_file 。
    video 输入图片列表形式的视频时需设为video。
    video_url 输入视频文件时需设为video_url。
   */
  type = 'text' as ChatMessageType;
  /**
   * 内容
   */
  content = '';
  /** 
   * 思考内容
   */
  reasoningContent = '';
  /**
   * 额外信息
   */
  extra?: string;
  /**
   * 回复ID，针对用户消息
   */
  replyItemId = 0;
  /**
   * 父级ID, 针对非用户消息，链接至用户消息
   */
  parentId = 0;
  /**
   * 推理时间ms
   */
  reasoningTime = 0;
  /**
   * 回复时间ms
   */
  replyTime = 0;
  /**
   * 回答AI名称
   */
  name = '';
  /**
   * 附件列表
   */
  files?: AgentChatFile[];

  //以下为前端临时使用
  //==========================================

  /**
   * tool 角色消息关联的 tool_call_id（仅前端临时使用）
   */
  tool_call_id?: string;
  /**
   * assistant 消息上携带的 tool_calls（仅前端临时使用）
   */
  toolCalls?: OpenAI.Chat.ChatCompletionMessageToolCall[];
  /**
   * 状态文本，仅用于临时界面显示，不保存数据库
   */
  statusText?: string;

  timestamp = new Date() as Date;
  /**
   * 动作列表，用于界面用户操作
   */
  actions?: string[];

  isEphemeral = false as boolean;
  
  /**
   * 会话ID（本地新建尚未落库时可空）
   */
  historyId?: number;
  /** 
   * 后端聊天记录项 id（本地新建尚未落库时可空）
   */
  historyItemId?: number;

  /**
   * 输入的图片信息。当type为image_url时是必选参数。
   */
  image_url?: string;
  /**
   * 输入的音频信息。当type为input_audio时是必选参数。
   */
  input_audio?: {
    /**
     * 音频的 URL 或Base64 Data URL
     */
    data: string;
    /**
     * 输入音频的格式，如mp3、wav等。
     */
    format: string;
  };
  /**
   * 输入的音频文件信息。当type为audio_url时是必选参数。
   */
  audio_url?: string;
  /**
   * 输入的视频信息。当type为video时是必选参数。
   */
  video?: string[];
  /**
   * 输入的视频文件信息。当type为video_url时是必选参数。
   */
  video_url?: string;
  /**
   * 输入的文件ID。当type为input_file时是必选参数。
   */
  file_id?: string;


  get isReplied() {
    return this.replyItemId > 0;
  }
  /**
   * 是否已持久化
   */
  get isPersisted() {
    return this.id > 0;
  }
  get isUser() {
    return this.role === 'user';
  }
  get isAssistant() {
    return this.role === 'assistant';
  }
  get isSystem() {
    return this.role === 'system';
  }
  get isTool() {
    return this.role === 'tool';
  }
  get isMedia() {
    return this.type === 'image_url' || this.type === 'video' 
    || this.type === 'video_url' || this.type === 'input_audio' || this.type === 'input_file';
  }

  constructor(props?: Partial<ChatMessage>) {
    if (props)
      Object.assign(this, props);
  }

  setError(title: string, error: string) {
    this.statusText = title;
    this.extra = error.trim() ? error : undefined;
    this.state = 'error';
  }
  resetError() {
    this.statusText = undefined;
    this.extra = undefined;
    this.state = 'loading';
  }

  static fromHistoryItem(item: AgentChatHistoryItem): ChatMessage {
    const message = new ChatMessage();
    message.role = item.role as ChatMessageRole;
    message.timestamp = item.date;
    message.historyId = item.historyId;
    message.historyItemId = item.id;
    message.replyItemId = item.replyItemId;
    message.parentId = item.parentId;
    message.reasoningTime = item.reasoningTime;
    message.replyTime = item.replyTime;
    message.name = item.name;
    message.id = item.id;
    message.content = item.content;
    message.extra = item.extra;
    message.reasoningContent = item.reasoningContent;
    message.files = item.files;
    message.state = item.state as ChatMessageState;
    message.type = item.type as ChatMessageType;
    switch (message.type) {
      case 'image_url':
        message.image_url = message.files?.[0]?.url || item.content;
        break;
      case 'video_url':
        message.video_url = message.files?.[0]?.url || item.content;
        break;
      case 'input_audio':
        message.input_audio = {
          data: message.files?.[0]?.url || item.content,
          format: StringUtils.path.getFileExt(message.files?.[0]?.url || '') || 'mp3',
        };
        break;
      case 'video':
        message.video = [ message.files?.[0]?.url || item.content ];
        break;
      case 'input_file':
        message.content = item.content;
        message.file_id = message.files?.[0]?.aiFileId || '';
        break;
      default:
        message.content = item.content;
        break;
    }
    return message;
  }
  toHistoryItem(): AgentChatHistoryItem {
    const temp = new AgentChatHistoryItem().setSelfValues({
      id: this.id > 0 ? this.id : undefined,
      role: this.role,
      state: this.state,
      reasoningContent: this.reasoningContent,
      content: this.content,
      extra: this.extra,
      type: this.type,
      historyId: this.historyId,
      date: this.timestamp,
      replyItemId: this.replyItemId,
      parentId: this.parentId,
      reasoningTime: this.reasoningTime,
      replyTime: this.replyTime,
      name: this.name,
    });
    switch (this.type) {
      case 'image_url':
        temp.content = this.image_url || '';
        break;
      case 'input_audio':
        temp.content = this.input_audio?.data || '';
        break;
      case 'input_file':
        temp.content = this.content;
        break;
      case 'video':
        //TODO: 多个文件数据
        temp.content = this.video?.[0] || '';
        break;
      case 'video_url':
        temp.content = this.video_url || '';
        break;
      default:
        temp.content = this.content;
        break;
    }
    return temp;
  }
  toAi() {
    switch (this.role) {
      case 'tool':
        return {
          role: 'tool',
          tool_call_id: this.tool_call_id,
          content: this.content + (this.extra ? `\n\n${this.extra}` : ''),
        } as OpenAI.Chat.ChatCompletionToolMessageParam;
      case 'assistant':
        return {
          role: 'assistant',
          content: this.content || this.reasoningContent,
          tool_calls: this.toolCalls?.length ? this.toolCalls : undefined,
        } as OpenAI.Chat.ChatCompletionAssistantMessageParam;
      case 'user': {
        switch (this.type) {
          case 'image_url':
            return {
              type: 'image_url',
              role: 'user',
              content: undefined as any,
              image_url: {
                url: this.image_url
              },
            } as OpenAI.Chat.ChatCompletionUserMessageParam;
          case 'input_audio':
            return {
              type: 'input_audio',
              role: 'user',
              content: undefined as any,
              input_audio: this.input_audio,
            } as OpenAI.Chat.ChatCompletionUserMessageParam;
          case 'input_file':
            return {
              type: 'input_file',
              role: 'user',
              content: undefined as any,
              file_id: this.file_id,
            } as OpenAI.Chat.ChatCompletionUserMessageParam;
          case 'video':
            return {
              type: 'video',
              role: 'user',
              content: undefined as any,
              video: this.video,
            } as OpenAI.Chat.ChatCompletionUserMessageParam;
          case 'video_url':
            return {
              type: 'video_url',
              role: 'user',
              content: undefined as any,
              video_url: {
                url: this.video_url,
              },
            } as OpenAI.Chat.ChatCompletionUserMessageParam;
          default:
            return {
              role: 'user',
              content: this.content,
            } as OpenAI.Chat.ChatCompletionUserMessageParam;
        }
      }
      case 'system':
        return {
          role: 'system',
          content: this.content,
        } as OpenAI.Chat.ChatCompletionSystemMessageParam;
      default:
        return undefined
    }
  }

  static createUser(content: string, newId: number): ChatMessage {
    const message = new ChatMessage();
    message.content = content;
    message.role = 'user';
    message.state = 'success';
    message.id = newId;
    return message;
  }

  static async createAttachment(attachment: ChatAttachmentItem, newId: number): Promise<ChatMessage> {
    const message = new ChatMessage();
    message.content = attachment.name;
    message.role = 'user';
    message.files = [ new AgentChatFile().setSelfValues({
      id: attachment.id,
      path: attachment.path,
      url: attachment.url,
    }) ];
    switch (attachment.type) {
      case 'image':
        message.type = 'image_url';
        message.image_url = attachment.url;
        break;
      case 'audio':
        message.type = 'input_audio';
        message.input_audio = {
          data: attachment.url || '',
          format: StringUtils.path.getFileExt(attachment.url || '') || 'mp3',
        };
        break;
      case 'video':
        message.type = 'video';
        message.video = [ attachment.url || '' ];
        break;
      case 'document':
        message.type = 'input_file';
        break;
      case 'text': {
        message.type = 'text';
        const file = attachment.file;
        if (file) {
          const text = await file.text();
          message.content = `## ${attachment.name}\n\`\`\`text\n` + text + '\n\`\`\`';
        } else {
          message.content = `[${attachment.name}](${attachment.url})`;
        }
        break;
      }
    }
    message.timestamp = new Date();
    message.state = 'success';
    message.id = newId;
    return message;
  }

  static createUserAudio(input_audio: string, newId: number): ChatMessage {
    const message = new ChatMessage();
    message.type = 'input_audio';
    message.input_audio = {
      data: input_audio,
      format: StringUtils.path.getFileExt(input_audio) || 'mp3',
    };
    message.timestamp = new Date();
    message.state = 'success';
    message.id = newId;
    return message;
  }

  static createAssistant(content: string, newId: number, state: ChatMessageState = 'success'): ChatMessage {
    const message = new ChatMessage();
    message.content = content;
    message.role = 'assistant';
    message.timestamp = new Date();
    message.state = state;
    message.id = newId;
    return message;
  }

  static createEphemeralAssistant(content: string, newId: number): ChatMessage {
    const message = new ChatMessage();
    message.content = content;
    message.role = 'assistant';
    message.isEphemeral = true;
    message.timestamp = new Date();
    message.state = 'success';
    message.id = newId;
    return message;
  }

  static createSystem(content: string): ChatMessage {
    const message = new ChatMessage();
    message.content = content;
    message.role = 'system';
    message.timestamp = new Date();
    return message;
  }

  static createTool(name: string, content: string, newId: number): ChatMessage {
    const message = new ChatMessage();
    message.content = content;
    message.role = 'tool';
    message.timestamp = new Date();
    message.state = 'loading';
    message.id = newId;
    return message;
  }
}