import { AIMessage, HumanMessage } from 'langchain/schema'
import { StructuredOutputParser } from 'langchain/output_parsers'
import { z } from 'zod'
import { uploadUml } from './upload'
import { createLLM } from './llm'
import { Logger } from '@nestjs/common'
import { LLMTools } from './types'
async function genRoles(tools, title, desc) {
    const { llm, usage, conversation } = tools

    const scheme = StructuredOutputParser.fromZodSchema(
        z.array(
            z.object({
                roleName: z.string().describe('角色名称'),
                roleDesc: z.string().describe('角色描述')
            })
        )
    )
    const { content } = await llm.call([
        new HumanMessage(`${scheme.getFormatInstructions()}
------
我正在做一个项目：${title}
这个项目包含以下功能：
${desc}
现在我们分析一下这个项目中有以下几个角色：`)
    ])
    return await scheme.parse(content)
}
export async function _createUseCase(tools: LLMTools, title, desc, roles, i) {
    const { llm } = tools

    let { content: code } = await llm.call([
        new HumanMessage(`我的毕业设计项目是${title}
这个项目包含以下功能：
${desc}

现在我们分析一下这个项目中有以下几个角色：`),
        new AIMessage(`根据你提供的功能描述，这个项目中有以下几个角色：
${roles.map((e, i) => `${i + 1}. ${e.roleName}: ${e.roleDesc}`).join('\n')}
这些角色在系统中扮演不同的角色和拥有不同的权限，以实现系统的各种功能。`),
        new HumanMessage(`现在请你用plantUML语言描述一下${roles[i].roleName}的用例图`)
    ])
    code = /\`\`\`(?:plantuml)?([\s\S]+)\`\`\`/.exec(code)[1]
    const url = await uploadUml(code)
    return { name: `${roles[i].roleName}`, url, desc: `${roles[i].roleDesc}` }
}

export async function createUseCase(tools: LLMTools, title, desc) {
    const pRetry = (await eval("import('p-retry')")).default
    const roles = await pRetry(() => genRoles(tools, title, desc), {
        retries: 5,
        onFailedAttempt: (error) => {
            Logger.error(error.message, error.stack, 'CreateUseCase Error')
        }
    })
    return Promise.all(
        roles.map((role, i) =>
            pRetry(() => _createUseCase(tools, title, desc, roles, i), {
                retries: 5,
                onFailedAttempt: (error) => {
                    Logger.error(error.message, error.stack, 'CreateUseCase Error')
                }
            })
        )
    )
}
