import { Message, SendableChannels } from 'discord.js'
import { ChatResponse, Ollama } from 'ollama'
import { ChatParams, UserMessage, streamResponse, blockResponse } from './index.js'
import { Queue } from '../queues/queue.js'
import { AbortableAsyncIterator } from 'ollama/src/utils.js'

/**
 * Method to send replies as normal text on discord like any other user
 * @param message message sent by the user
 * @param model name of model to run query
 * @param msgHist message history between user and model
 */
export async function normalMessage(
    message: Message,
    ollama: Ollama,
    model: string,
    msgHist: Queue<UserMessage>,
    stream: boolean
): Promise<string> {
    // bot's respnse
    let response: ChatResponse | AbortableAsyncIterator<ChatResponse>
    let result: string = ''
    const channel = message.channel as SendableChannels

    await channel.send('Generating Response . . .').then(async sentMessage => {
        try {
            const params: ChatParams = {
                model: model,
                ollama: ollama,
                msgHist: msgHist.getItems()
            }

            // run query based on stream preference, true = stream, false = block
            if (stream) {
                let messageBlock: Message = sentMessage
                response = await streamResponse(params) // THIS WILL BE SLOW due to discord limits!
                for await (const portion of response) {
                    // check if over discord message limit
                    if (result.length + portion.message.content.length > 2000) {
                        result = portion.message.content

                        // new message block, wait for it to send and assign new block to respond.
                        await channel.send("Creating new stream block...")
                            .then(sentMessage => { messageBlock = sentMessage })
                    } else {
                        result += portion.message.content

                        // ensure block is not empty
                        if (result.length > 5)
                            messageBlock.edit(result)
                    }
                    console.log(result)
                }
            }
            else {
                response = await blockResponse(params)
                result = response.message.content

                // check if there is a <think>...</think> sequence from the bot.
                if (hasThinking(result))
                    result = result.replace(/<think>[\s\S]*?<\/think>/g, '').trim()

                // check if message length > discord max for normal messages
                if (result.length > 2000) {
                    sentMessage.edit(result.slice(0, 2000))
                    result = result.slice(2000)

                    // handle for rest of message that is >2000
                    while (result.length > 2000) {
                        channel.send(result.slice(0, 2000))
                        result = result.slice(2000)
                    }

                    // last part of message
                    channel.send(result)
                } else // edit the 'generic' response to new message since <2000
                    sentMessage.edit(result)
            }
        } catch (error: any) {
            console.log(`[Util: messageNormal] Error creating message: ${error.message}`)
            if (error.message.includes('fetch failed'))
                error.message = 'Missing ollama service on machine'
            else if (error.message.includes('try pulling it first'))
                error.message = `You do not have the ${model} downloaded. Ask an admin to pull it using the \`pull-model\` command.`
            sentMessage.edit(`**Response generation failed.**\n\nReason: ${error.message}`)
        }
    })

    // return the string representation of ollama query response
    return result
}

export async function summarizeContextHistory(
    ollama: Ollama, 
    model: string, 
    msgHist: UserMessage[], 
): Promise<string> {
    // todo: this stuff to create a response in a simpler way!
    try {
            const params: ChatParams = {
            model: model,
            ollama: ollama,
            msgHist: msgHist
        }
        const response: ChatResponse = await blockResponse(params)
        let result = response.message.content

        if (hasThinking(result))
            result = result.replace(/<think>[\s\S]*?<\/think>/g, '').trim()

        return result
    } catch (error: any) {
        console.log(`[Util: messageNormal] Error creating message: ${error.message}`)
        if (error.message.includes('fetch failed'))
            error.message = 'Missing ollama service on machine'
        else if (error.message.includes('try pulling it first'))
            error.message = `You do not have the ${model} downloaded. Ask an admin to pull it using the \`pull-model\` command.`
        return `**Response generation failed.**\n\nReason: ${error.message}`
    }
}
    

// Region: Helpers
function hasThinking(message: string): boolean {
    return /<think>[\s\S]*?<\/think>/i.test(message)
}
// End Region: Helpers
