/**
 * 微软AZure OpenAI
 */
import OpenAIBase from "./openaibase"
import { AzureOpenAIPatameters, ChatReponse, EmbeddingResult, OpenAIApiParameters} from "./declare";
import { OpenAIClient, AzureKeyCredential } from "@azure/openai";
export default class AzureAI extends OpenAIBase<OpenAIClient> {

    protected readonly azureSetting: AzureOpenAIPatameters;
    constructor(apiKey: string, azureOption: AzureOpenAIPatameters, apiOption: OpenAIApiParameters = {}) {
        super(apiKey, apiOption);
        this.azureSetting = azureOption;
        if (!this.azureSetting.endpoint.toLowerCase().startsWith('https://')) {
            this.azureSetting.endpoint = 'https://' + this.azureSetting.endpoint;
        }
    }
    /**
     * 初始化OpenAI 的聊天对象Api
     */
    createOpenAI(apiKey: string): OpenAIClient {
        return new OpenAIClient(this.azureSetting.endpoint, new AzureKeyCredential(apiKey));
    }

    get EmbeddingUrl(): string {
        return `${this.azureSetting.endpoint}/openai/deployments/${this.embeddingmodel || 'openai-embedding-ada-002'}/embeddings?api-version=2022-12-01`
    }

    /**
     * 获得文字的向量
     * @param text 
     */
    override async getTextEmbedding(text: string|string[], callOption: any = {}): Promise<EmbeddingResult> {
        if (!text) return { successed: false, error: { errcode: 2, errmsg: 'content required' } };
        if (!this.aiApi) this.aiApi = this.createOpenAI(this.apiKey);
        try{
            const result = await this.aiApi.getEmbeddings(this.embeddingmodel || 'openai-embedding-ada-002', typeof text === 'string' ? [text] : text, callOption)
            return { successed: true, embedding:result.data };
        }
        // if (!axiosOption.headers)
        //     axiosOption.headers = { 'api-key': this.apiKey, 'Content-Type': 'application/json' };
        // else {
        //     axiosOption.headers['api-key'] = this.apiKey;
        //     axiosOption.headers['Content-Type'] = 'application/json';
        // }

        // try {
        //     let param = {
        //         ...axiosOption,
        //         method: "post",
        //         data: {
        //             input: text
        //         },
        //         url: this.EmbeddingUrl
        //     };
        //     const response = await request(param)
        //     if (response.successed && response.data) {
        //         return { successed: true, embedding: response.data.data[0].embedding };
        //     }
        //     return { successed: false, ...response.data };
        catch (error) {
            return { successed: false, error };
        }
    }

    /**
     * 非流式聊天请求
     * @param _chatText 
     * @param _paramOption 
     * @param _axiosOption 
     */
    public async chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, _axiosOption: any = {}): Promise<ChatReponse> {
        if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
        if (!this.aiApi) this.aiApi = this.createOpenAI(this.apiKey);

        let message: Array<any> = typeof (chatText) == 'string' ?
            [{ role: 'user', content: chatText }] : chatText;
        try {
            const response: any = await this.aiApi.getChatCompletions(
                callChatOption?.model || this.chatModel,
                message,
                {
                    temperature: Number(callChatOption?.temperature || this.temperature),
                    maxTokens: Number(callChatOption?.maxtoken || this.maxtoken),
                    topP: Number(callChatOption?.top_p || this.top_p),
                    presencePenalty: Number(callChatOption?.presence_penalty || this.presence_penalty),
                    frequencyPenalty: Number(callChatOption?.frequency_penalty || this.frequency_penalty),
                    n: Number(callChatOption?.replyCounts || 1) || 1,
                    tools: (callChatOption?.enableToolCall === 1 && callChatOption?.tools) ? callChatOption.tools : undefined,
                    toolChoice: callChatOption?.enableToolCall === 1 ? 'auto' : undefined
                });
            const { promptTokens: prompt_tokens, completionTokens: completion_tokens, totalTokens: total_tokens } = response.usage
            let rebuildChoice = [];
            for (const msg of response.choices) {
                const { index, finishReason: finish_reason, message } = msg
                rebuildChoice.push({ index, finish_reason, message })
            }
            // if (response.data.choices[0].finish_reason === 'content_filter') {
            //     console.log('content_filter');
            //     return { successed: false, error: 'content_filter' };
            // }
            return { successed: true, message: rebuildChoice, usage: { prompt_tokens, completion_tokens, total_tokens } };

        } catch (error) {
            console.log('result is error ', error)
            return { successed: false, error };
        }

    }

    /**
     * 流式的聊天模式
     * @param chatText 
     * @param _paramOption 
     * @param axiosOption 
     */
    override async chatRequestInStream(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, attach?: any, axiosOption?: any): Promise<any> {
        if (!chatText) this.emit('chaterror', { successed: false, error: 'no text in chat' });
        if (!this.aiApi) {
            this.aiApi = this.createOpenAI(this.apiKey);
        }
        let message: Array<any> = typeof (chatText) == 'string' ?[{ role: 'user', content: chatText }] : chatText;
        axiosOption = Object.assign({}, axiosOption || { timeout: 60000 })
        let requestid = Math.ceil(Math.random() * (new Date().getTime() * Math.random()) / 1000);
        let has_tool_calls=0,currentIndex, previous_index=-1, tool_calls:any[] = [];// 使用数组来存储工具调用
        try {
            const response: any = await this.aiApi.streamChatCompletions(
                callChatOption?.model || this.chatModel,
                message,
                {
                    temperature: Number(callChatOption?.temperature || this.temperature),
                    maxTokens: Number(callChatOption?.maxtoken || this.maxtoken),
                    topP: Number(callChatOption?.top_p || this.top_p),
                    presencePenalty: Number(callChatOption?.presence_penalty || this.presence_penalty),
                    frequencyPenalty: Number(callChatOption?.frequency_penalty || this.frequency_penalty),
                    n: Number(callChatOption?.replyCounts || 1) || 1,
                    tools: (callChatOption?.enableToolCall===1 && callChatOption?.tools) ? callChatOption.tools : undefined,
                    toolChoice: callChatOption?.enableToolCall === 1 ?'auto':undefined
                });
            //console.log('tools', callChatOption.enableToolCall, callChatOption.tools)
            let replytext: string[] = [];
            for await (const event of response) {
                for (const choice of event.choices) {
                    const { finishReason: finishreason, index } = choice;
                    const toolCalls = choice.delta?.toolCalls;
                    ///存在了toolCalls
                    if (toolCalls && toolCalls.length){
                        currentIndex = toolCalls[0].index;
                        has_tool_calls = 1;
                        // 检查index是否发生变化
                        //console.log('currentIndex,previous_index', currentIndex, previous_index)
                        if (currentIndex !== previous_index) {
                            tool_calls.push({
                                id: toolCalls[0].id,
                                type: 'function',
                                function: {
                                    name: toolCalls[0].function.name,
                                    arguments: toolCalls[0].function.arguments
                                }
                            });
                            // 更新previousIndex以供下次比较
                            previous_index = currentIndex;
                        } else {
                            tool_calls[previous_index].function.arguments += toolCalls[0].function.arguments
                        }
                    }else{
                        const content = choice.delta?.content;
                        replytext.push(content);
                    }
                    let output = { successed: true, requestid, segment: choice.delta?.content, text: replytext.join(''), finish_reason: finishreason, index, has_tool_calls: has_tool_calls, tool_calls: tool_calls };
                    if (attach) output = Object.assign({}, output, attach);
                    this.emit(finishreason ? 'chatdone' : 'chattext', output)
                }
            }
            return { successed: true, requestid }
        } catch (error) {
            this.emit('requesterror', { successed: false, requestid, error: 'call axios faied ' +error });
            return { successed: false, requestid }
        }
    }
}