<template>
    <view v-if="rulesInit" class="mt-40 flex flex-col gap-30">
        <view v-for="(r,i) in renderRules.filter(i => i.details?.length)" :key="i" class="flex flex-col gap-30">
            <view class="text-32 font-bold">{{ r.category }}</view>
            <uv-form ref="form" :model="model" :rules="rules" label-position="top">
                <uv-form-item v-for="d in r.details" :key="d.fieldName" :prop="d.fieldName">
                    <view class="flex-1 flex items-center justify-between gap-40">
                        <text class="text-30 text-fore-title" :style="{width: getLabelWidth(r)}">{{ d.label }}</text>
                        <uv-input v-model="model[d.fieldName]" :disabled="d.readonly"
                                  :placeholder="d.placeholder || '请输入'"
                                  :suffix-icon="d.readonly ? 'lock': undefined"/>
                        <text class="text-28 text-fore-placeholder">(总分 {{ d.options.toString() }})</text>
                    </view>
                </uv-form-item>
            </uv-form>
        </view>
    </view>
</template>

<script setup lang="ts">
import {VOLUNTARY_RULES, VOLUNTARY_MODEL} from "@/types/injectionSymbols";
import {EnrollRule, EnrollRuleItem, VoluntaryModel} from "@/types/voluntary";
import _ from "lodash";

const renderRules = inject(VOLUNTARY_RULES) || ref<EnrollRule[]>()
const model = inject(VOLUNTARY_MODEL) || ref<VoluntaryModel>({})
const form = ref<{ validate: () => Promise<void> }[]>()
const rules = ref({})
const rulesInit = ref(false)

const getLabelWidth = function (rule: EnrollRule) {
    const maxLen = _.maxBy(rule.details, d => d.label.length)
    return (maxLen?.label.length || 2) * 30 + 'rpx'
}

const validate = () => {
    if (!form.value) return
    const validates = form.value.map(f => f.validate())
    return Promise.all(validates)
}

watch([renderRules, model], ([renderRules, model]) => {
    if (!renderRules || !model) return
    const autoRules: Record<string, any> = {}
    renderRules.forEach((item: EnrollRule) => {
        item.details?.forEach((r: EnrollRuleItem) => {
            // TODO: 此规则逻辑从旧的uni-vueuse mx-base分支迁移过来，可能不完全适用于新版本。
            const fieldRules = []
            // 录取规则，自动添加非空校验
            if (r.enumRuleCategory == 'Enroll') {
                fieldRules.push({required: true, message: `请填写${r.label}分数`})
            }
            // 分制类型的输入，要同时校验分制与得分
            if (r.enumInputType == 'Score') {
                fieldRules.push({
                    validator: (_r: any, _v: any, cb: (arg0: string | undefined) => void) => {
                        const fieldTotal = r.fieldName + 'Total'
                        let score = Number(model[r.fieldName]) || 0
                        let total = Number(model[fieldTotal]) || 0
                        if (!total) {
                            cb(`请选择总分`)
                            return
                        }
                        if (!score) {
                            cb(`请填写${r.label}分数`)
                            return
                        }
                        if (score < 0 || score > total) {
                            cb(`分数不能超过总分${total}`)
                            return
                        }
                        cb(undefined)
                    }
                })
            }
            const hasVal = (val: any) => val !== null && val !== undefined
            if (hasVal(r.min) || hasVal(r.max)) {
                const createRangeMsg = () => {
                    if (r.enumInputType == 'Text') {
                        if (hasVal(r.min) && hasVal(r.max)) return `长度必须在${r.min}-${r.max}个字符之间`
                        if (hasVal(r.min)) return `长度至少${r.min}个字符`
                        if (hasVal(r.max)) return `长度不超过${r.max}个字符`
                    } else if (r.enumInputType == 'Number') {
                        if (hasVal(r.min) && hasVal(r.max)) return `数值必须在${r.min}-${r.max}之间`
                        if (hasVal(r.min)) return `数值不能小于${r.min}`
                        if (hasVal(r.max)) return `数值不能大于${r.max}`
                    } else if (r.enumInputType == 'Checkbox') {
                        if (hasVal(r.min) && hasVal(r.max)) return `必须选择${r.min}-${r.max}项`
                        if (hasVal(r.min)) return `至少选择${r.min}项`
                        if (hasVal(r.max)) return `至多选择${r.max}项`
                    }
                }
                const createRangeType = () => {
                    switch (r.enumInputType) {
                        case 'Number':
                        case 'Score':
                            return 'number'
                        case 'Checkbox':
                            return 'array'
                        default:
                            return 'string'
                    }
                }
                const rangeRule : {
                    type: string,
                    min?: number,
                    max?: number,
                    message: string | undefined
                    transform?: (val: any) => any
                } = {
                    type: createRangeType(),
                    min: r.min,
                    max: r.max,
                    message: createRangeMsg()
                }
                if (!hasVal(r.min)) delete rangeRule.min
                if (!hasVal(r.max)) delete rangeRule.max
                if (r.enumInputType == 'Number')
                    rangeRule.transform = val => hasVal(val) ? val * 1 : val
                fieldRules.push(rangeRule)
            }
            if (r.regex) {
                fieldRules.push({
                    pattern: r.regex,
                    message: `${r.label}格式不符合要求`
                })
            }
            if (fieldRules.length) autoRules[r.fieldName] = fieldRules
        })
    })
    rules.value = autoRules
    rulesInit.value = true
}, {immediate: true})

defineExpose({validate})
</script>

<style scoped>

</style>