<template>
    <div>
        <div class="">
            <ElSelect v-model="type">
                <ElOption v-for="item in types" :key="item" :label="item" :value="item" />
            </ElSelect>
            <ElButton :icon="Plus" class="ml-4" @click="addType"></ElButton>
            <ElButton :icon="Trash" @click="delType" />
        </div>
        <el-tabs v-model="activeName" class="mt-4" tabPosition="left">
            <el-tab-pane v-for="(item, i) in prompts" :key="item.name" :label="item.description" :name="item.name">
                <ElInput v-model="item.template" type="textarea" :autosize="{ min: 20 }"></ElInput>
                <div class="mt-4">
                    <ElButton @click="save(i)" :loading="loading" type="primary">保存</ElButton>
                    <ElButton @click="test(i)" :loading="loading">测试</ElButton>
                    <ElButton @click="restore(i)" :disabled="loading">恢复默认</ElButton>
                </div>
            </el-tab-pane>
        </el-tabs>
        <br />
        <br />
        <div class="ml-32 flex text-sm text-neutral-600 dark:text-neutral-400">
            <div class="">
                可用变量：<br />
                days: 运行天数<br />
                charactors: 角色列表<br />
                total: 总人数<br />
                alive: 存活人数<br />
                dead: 死亡人数<br />
                minHp: 最低生命值<br />
                maxHp: 最高生命值<br />
                avgHp: 平均生命值<br /><br />
                语法示例:
                <code class="bg-neutral-300 dark:bg-neutral-700 px-2 py-1 rounded-sm"
                    >&lt;% return alive > 5 ? '加入战斗情节' : '' %&gt;</code
                ><br />
                <br />
            </div>
            <div class="pl-8">
                测试变量:<br />
                <json-viewer :value="testVarsFinal" :expand-depth="1" copyable boxed sort></json-viewer>
            </div>
        </div>
    </div>
</template>
<script setup>
import { http } from '@/plugins/http'
import { onMounted, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, Trash } from '@vicons/tabler'
import { ElMessageBox } from 'element-plus'
import JsonViewer from 'vue-json-viewer'
import {} from '@vicons/tabler'
const activeName = ref('')
const prompts = ref([])
const types = ref([])
const type = ref(null)
const props = defineProps({
    gameId: {
        type: Number,
        default: 0
    }
})
function load() {
    http.get('/prompt/types').then((res) => {
        types.value = res
        if (res.length === 0) {
            type.value = null
            prompts.value = []
        } else {
            if (!type.value) {
                type.value = res[0]
            } else if (!res.find((item) => item === type.value)) {
                type.value = res[0]
            }
        }
    })
}
watch(type, (val) => {
    if (val) {
        http.get(`/prompt/${val}`).then((res) => {
            prompts.value = res
        })
    }
})
onMounted(() => {
    load()
})
const loading = ref(false)
async function save(i) {
    if (!test(i, false)) {
        return
    }
    try {
        loading.value = true
        await http.put('/prompt', prompts.value[i])
        loading.value = false
        ElMessage.success('保存成功')
    } catch (error) {
        loading.value = false
        ElMessage.error(error.message)
    }
}
async function restore(i) {
    prompts.value[i].template = prompts.value[i].defaultTemplate
}
async function addType() {
    const { value: type } = await ElMessageBox.prompt('请输入类型', '添加类型', {
        inputPattern: /.+/,
        inputErrorMessage: '请输入类型'
    })
    console.log(type)
    try {
        await http.put(`/prompt/types`, { type })
        ElMessage.success('添加成功')
        load()
    } catch (error) {
        ElMessage.error(error.message)
    }
}
async function delType() {
    await ElMessageBox.confirm('确定删除该类型吗？', '删除类型', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    })
    try {
        await http.delete(`/prompt/${type.value}`)
        ElMessage.success('删除成功')
        load()
    } catch (error) {
        ElMessage.error(error.message)
    }
}
const testVars = {
    days: 4,
    charactors: [
        {
            name: '约翰',
            gender: '男',
            age: '35',
            occupation: '侦探',
            personality: '1号',
            background: '前警探，以侦破神秘犯罪而闻名',
            hp: 0,
            joinAt: '2023-10-10T16:00:00.000Z',
            survival: 0,
            dead: true,
            avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/7laitqdb.png',
            deadAt: '2023-10-15T16:00:00.000Z'
        },
        {
            name: '艾米丽',
            gender: '女',
            age: '28',
            occupation: '记者',
            personality: '好奇心重',
            background: '调查性记者，专注于揭露黑暗的秘密。',
            hp: 0,
            joinAt: '2023-10-10T16:00:00.000Z',
            survival: 0,
            dead: true,
            avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/dgg7bxc6.png',
            deadAt: '2023-10-14T16:00:00.000Z'
        },
        {
            name: '威廉',
            gender: '女',
            age: '45',
            occupation: '律师',
            personality: '聪明的',
            background: '非常成功的辩护律师，以为自己的客户获得无罪声誉而闻名。',
            hp: 10,
            joinAt: '2023-10-10T16:00:00.000Z',
            survival: 0,
            dead: false,
            avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/slxskike.png'
        },
        {
            name: '伊莎贝拉',
            gender: '女',
            age: '30',
            occupation: '法医',
            personality: '善于分析',
            background: '具有DNA分析专业知识的法医科学家，解决了许多冷案。',
            hp: 0,
            joinAt: '2023-10-10T16:00:00.000Z',
            survival: 0,
            dead: true,
            avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/oqqliuus.png',
            deadAt: '2023-10-14T16:00:00.000Z'
        },
        {
            name: '亚历山大',
            gender: '男',
            age: '40',
            occupation: '心理学家',
            personality: '富有洞察力的',
            background: '著名心理学家，专长是犯罪心理分析。',
            hp: 10,
            joinAt: '2023-10-10T16:00:00.000Z',
            survival: 0,
            dead: false,
            avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/hqflwm6u.png'
        }
    ]
}
function evalPrompt(vars, template) {
    vars.total = vars.charactors.length
    vars.alive = vars.charactors.filter((i) => !i.dead).length
    vars.dead = vars.charactors.filter((i) => i.dead).length
    const hps = vars.charactors.filter((i) => i.hp > 0).map((i) => i.hp)
    vars.minHp = hps.length > 0 ? Math.min(...hps) : 0
    vars.maxHp = hps.length > 0 ? Math.max(...hps) : 0
    vars.avgHp = hps.length > 0 ? hps.reduce((a, b) => a + b) / hps.length : 0
    const reg = /<%([^%]*(?:%(?!>)[^%]*)*)%>/
    while (reg.test(template)) {
        template = template.replace(reg, function (match, $1) {
            var func = new Function('days', 'charactors', 'total', 'alive', 'dead', 'minHp', 'maxHp', 'avgHp', $1)
            return func(
                vars.days,
                vars.charactors,
                vars.total,
                vars.alive,
                vars.dead,
                vars.minHp,
                vars.maxHp,
                vars.avgHp
            )
        })
    }
    return {
        template,
        vars
    }
}
const testVarsFinal = evalPrompt(testVars, '<% return alive > 5 ? "加入战斗情节" : "" %>').vars
function test(i, showResult = true) {
    try {
        const result = evalPrompt(testVars, prompts.value[i].template)
        if (showResult) {
            ElMessageBox.alert(`<p class="whitespace-pre-wrap">${result.template}</p>`, `测试结果`, {
                dangerouslyUseHTMLString: true,
                customStyle: { maxWidth: '800px' }
            })
        }
        return true
    } catch (error) {
        console.log(error)
        ElMessageBox.alert(`<p class="text-red-500">${error.message}</p>`, '测试失败', {
            type: 'error',
            dangerouslyUseHTMLString: true
        })
    }
    return false
}
</script>
