<template>
    <el-dialog
        class="ba-operate-dialog"
        :close-on-click-modal="false"
        :model-value="['Add', 'Edit'].includes(baTable.form.operate!)"
        @close="baTable.toggleForm"
    >
        <template #header>
            <div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">
                {{ baTable.form.operate ? t(baTable.form.operate) : '' }}
            </div>
        </template>
        <el-scrollbar v-loading="baTable.form.loading" class="ba-table-form-scrollbar">
            <div
                class="ba-operate-form"
                :class="'ba-' + baTable.form.operate + '-form'"
                :style="config.layout.shrink ? '' : 'width: calc(100% - ' + baTable.form.labelWidth! / 2 + 'px)'"
            >
                <el-form
                    v-if="!baTable.form.loading"
                    ref="formRef"
                    @submit.prevent=""
                    @keyup.enter="baTable.onSubmit(formRef)"
                    :model="baTable.form.items"
                    :label-position="config.layout.shrink ? 'top' : 'right'"
                    :label-width="baTable.form.labelWidth + 'px'"
                    :rules="rules"
                >
<!--                    <el-alert class="game-user-form-tip" type="info" :closable="false" show-icon>-->
<!--                        {{ t('user.user.form_tip') }}-->
<!--                    </el-alert>-->

                    <el-divider content-position="left">{{ t('user.user.section_basic') }}</el-divider>
                    <FormItem
                        :label="t('user.user.username')"
                        type="string"
                        v-model="baTable.form.items!.username"
                        prop="username"
                        :placeholder="t('Please input field', { field: t('user.user.username') })"
                    />
                    <FormItem
                        :label="t('user.user.password')"
                        type="password"
                        v-model="baTable.form.items!.password"
                        prop="password"
                        :placeholder="t('Please input field', { field: t('user.user.password') })"
                    />
                    <FormItem
                        :label="t('user.user.phone')"
                        type="string"
                        v-model="baTable.form.items!.phone"
                        prop="phone"
                        :placeholder="t('Please input field', { field: t('user.user.phone') })"
                    />
                    <FormItem
                        :label="t('user.user.email')"
                        type="string"
                        v-model="baTable.form.items!.email"
                        prop="email"
                        :placeholder="t('user.user.email_placeholder')"
                    />
                    <FormItem
                        :label="t('user.user.head_image')"
                        type="image"
                        v-model="baTable.form.items!.head_image"
                        prop="head_image"
                    />

                    <el-divider content-position="left">{{ t('user.user.section_admin_attribution') }}</el-divider>
                    <el-form-item :label="t('user.user.admin_affiliation')" prop="admin_id">
                        <el-tree-select
                            v-model="baTable.form.items!.admin_id"
                            class="w100"
                            clearable
                            filterable
                            :data="adminScopeTree"
                            :props="treeProps"
                            :render-after-expand="false"
                            :placeholder="t('user.user.admin_affiliation_placeholder')"
                            @update:model-value="onAdminTreeChange"
                        />
                    </el-form-item>
                    <FormItem
                        v-if="baTable.form.operate === 'Edit'"
                        :label="t('user.user.uuid')"
                        type="string"
                        v-model="baTable.form.items!.uuid"
                        prop="uuid"
                        :input-attr="{ readonly: true, disabled: true }"
                    />

                    <el-divider content-position="left">{{ t('user.user.section_register') }}</el-divider>
                    <FormItem
                        :label="t('user.user.register_invite_code')"
                        type="string"
                        v-model="baTable.form.items!.register_invite_code"
                        prop="register_invite_code"
                        :input-attr="{ readonly: true }"
                        :placeholder="t('user.user.register_invite_code_auto_placeholder')"
                    />

                    <el-divider content-position="left">{{ t('user.user.section_risk') }}</el-divider>
                    <el-form-item :label="t('user.user.risk_flags')">
                        <div class="risk-flag-row">
                            <el-tag
                                :type="riskBits.noLogin ? 'danger' : 'info'"
                                :effect="riskBits.noLogin ? 'dark' : 'plain'"
                                class="risk-flag-tag"
                                @click="riskBits.noLogin = !riskBits.noLogin"
                            >
                                {{ t('user.user.risk_no_login') }}
                            </el-tag>
                            <el-tag
                                :type="riskBits.noBet ? 'danger' : 'info'"
                                :effect="riskBits.noBet ? 'dark' : 'plain'"
                                class="risk-flag-tag"
                                @click="riskBits.noBet = !riskBits.noBet"
                            >
                                {{ t('user.user.risk_no_bet') }}
                            </el-tag>
                            <el-tag
                                :type="riskBits.noWithdraw ? 'danger' : 'info'"
                                :effect="riskBits.noWithdraw ? 'dark' : 'plain'"
                                class="risk-flag-tag"
                                @click="riskBits.noWithdraw = !riskBits.noWithdraw"
                            >
                                {{ t('user.user.risk_no_withdraw') }}
                            </el-tag>
                        </div>
                    </el-form-item>

                    <el-divider content-position="left">{{ t('user.user.section_streak') }}</el-divider>
                    <FormItem
                        :label="t('user.user.current_streak')"
                        type="number"
                        v-model="baTable.form.items!.current_streak"
                        prop="current_streak"
                        :input-attr="{ step: 1, min: 0, precision: 0 }"
                    />
                    <FormItem
                        :label="t('user.user.last_bet_period_no')"
                        type="string"
                        v-model="baTable.form.items!.last_bet_period_no"
                        prop="last_bet_period_no"
                        :placeholder="t('user.user.last_bet_period_no_placeholder')"
                    />

                    <el-divider content-position="left">{{ t('user.user.section_other') }}</el-divider>
                    <FormItem
                        :label="t('user.user.remark')"
                        type="textarea"
                        v-model="baTable.form.items!.remark"
                        prop="remark"
                        :input-attr="{ rows: 3 }"
                        @keyup.enter.stop=""
                        @keyup.ctrl.enter="baTable.onSubmit(formRef)"
                        :placeholder="t('Please input field', { field: t('user.user.remark') })"
                    />
                    <FormItem
                        :label="t('user.user.status')"
                        type="switch"
                        v-model="baTable.form.items!.status"
                        prop="status"
                        :input-attr="{ content: { '0': t('user.user.status 0'), '1': t('user.user.status 1') } }"
                    />
                </el-form>
            </div>
        </el-scrollbar>
        <template #footer>
            <div :style="'width: calc(100% - ' + baTable.form.labelWidth! / 1.8 + 'px)'">
                <el-button @click="baTable.toggleForm()">{{ t('Cancel') }}</el-button>
                <el-button v-blur :loading="baTable.form.submitLoading" @click="baTable.onSubmit(formRef)" type="primary">
                    {{ baTable.form.operateIds && baTable.form.operateIds.length > 1 ? t('Save and edit next item') : t('Save') }}
                </el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup lang="ts">
import type { FormItemRule } from 'element-plus'
import { inject, nextTick, onMounted, reactive, ref, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import FormItem from '/@/components/formItem/index.vue'
import { useConfig } from '/@/stores/config'
import type baTableClass from '/@/utils/baTable'
import { buildValidatorData, regularPassword } from '/@/utils/validate'
import createAxios from '/@/utils/axios'

const RISK_LOGIN = 1
const RISK_BET = 2
const RISK_WITHDRAW = 4

const config = useConfig()
const formRef = useTemplateRef('formRef')
const baTable = inject('baTable') as baTableClass

const { t } = useI18n()

type TreeNode = {
    value: string
    label: string
    disabled?: boolean
    children?: TreeNode[]
    channel_id?: number | null
    is_leaf?: boolean
    invite_code?: string
}

const adminScopeTree = ref<TreeNode[]>([])
const adminIdToChannelId = ref<Record<string, number>>({})
const adminIdToInviteCode = ref<Record<string, string>>({})
const currentAdminId = ref('')

const treeProps = {
    value: 'value',
    label: 'label',
    children: 'children',
    disabled: 'disabled',
}

const riskBits = reactive({
    noLogin: false,
    noBet: false,
    noWithdraw: false,
})

function syncRiskFromFlags(flags: unknown) {
    const f = typeof flags === 'number' ? flags : parseInt(String(flags ?? '0'), 10) || 0
    riskBits.noLogin = (f & RISK_LOGIN) !== 0
    riskBits.noBet = (f & RISK_BET) !== 0
    riskBits.noWithdraw = (f & RISK_WITHDRAW) !== 0
}

function packRiskFlags(): number {
    let r = 0
    if (riskBits.noLogin) r |= RISK_LOGIN
    if (riskBits.noBet) r |= RISK_BET
    if (riskBits.noWithdraw) r |= RISK_WITHDRAW
    return r
}

/** 璇嗗埆绠＄悊鍛樺彾瀛愶細value 闈?group_* 涓旀棤瀛愯妭鐐癸紙涓嶄緷璧?is_leaf锛岄伩鍏?el-tree 涓㈠純鑷畾涔夊瓧娈碉級 */
function isAdminTreeLeaf(n: TreeNode): boolean {
    const v = n.value
    if (v === undefined || v === null) return false
    if (String(v).startsWith('group_')) return false
    if (n.children && n.children.length > 0) return false
    return true
}

function buildAdminMapsFromTree(nodes: TreeNode[]) {
    const mapCh: Record<string, number> = {}
    const mapInv: Record<string, string> = {}
    const walk = (arr: TreeNode[]) => {
        for (const n of arr) {
            if (n.children?.length) {
                walk(n.children)
            }
            if (!isAdminTreeLeaf(n)) {
                continue
            }
            const id = String(n.value)
            if (n.channel_id !== undefined && n.channel_id !== null && n.channel_id !== '') {
                mapCh[id] = typeof n.channel_id === 'number' ? n.channel_id : parseInt(String(n.channel_id), 10)
            }
            if (typeof n.invite_code === 'string') {
                mapInv[id] = n.invite_code
            } else if (n.invite_code !== undefined && n.invite_code !== null) {
                mapInv[id] = String(n.invite_code)
            } else {
                mapInv[id] = ''
            }
        }
    }
    walk(nodes)
    return { mapCh, mapInv }
}

/** 鏄犲皠鏈懡涓椂浠庡師濮嬫爲鏌ユ壘锛堥槻姝?props 瑁佸壀鎴栧紓姝ユ椂搴忛棶棰橈級 */
function findAdminMetaInTree(nodes: TreeNode[], adminId: string): { channel_id?: number; invite_code: string } | null {
    const target = String(adminId).trim()
    for (const n of nodes) {
        if (n.children?.length) {
            const nested = findAdminMetaInTree(n.children, adminId)
            if (nested) {
                return nested
            }
        }
        if (!isAdminTreeLeaf(n)) {
            continue
        }
        if (String(n.value) !== target) {
            continue
        }
        let channelId: number | undefined
        if (n.channel_id !== undefined && n.channel_id !== null && n.channel_id !== '') {
            channelId = typeof n.channel_id === 'number' ? n.channel_id : parseInt(String(n.channel_id), 10)
        }
        const invite =
            typeof n.invite_code === 'string' ? n.invite_code : n.invite_code != null ? String(n.invite_code) : ''
        return { channel_id: channelId, invite_code: invite }
    }
    return null
}

const loadAdminScopeTree = async () => {
    const res = await createAxios({
        url: '/admin/user.User/adminScopeTree',
        method: 'get',
    })
    const list = (res.data?.list ?? []) as TreeNode[]
    const currentIdRaw = res.data?.current_admin_id
    currentAdminId.value = currentIdRaw === undefined || currentIdRaw === null ? '' : String(currentIdRaw)
    adminScopeTree.value = list

    const { mapCh, mapInv } = buildAdminMapsFromTree(list)
    adminIdToChannelId.value = mapCh
    adminIdToInviteCode.value = mapInv

    await nextTick()
    if (
        baTable.form.operate === 'Add' &&
        baTable.form.items &&
        (baTable.form.items.admin_id === undefined || baTable.form.items.admin_id === null || baTable.form.items.admin_id === '') &&
        currentAdminId.value !== ''
    ) {
        baTable.form.items.admin_id = currentAdminId.value
    }
    const aid = baTable.form.items?.admin_id
    if (aid !== undefined && aid !== null && aid !== '') {
        onAdminTreeChange(aid as string | number)
    }
}

const onAdminTreeChange = (val: string | number | null) => {
    if (!baTable.form.items) {
        return
    }
    if (val === null || val === undefined || val === '') {
        baTable.form.items.register_invite_code = ''
        return
    }
    const key = typeof val === 'number' ? String(val) : String(val).trim()

    let channelId = adminIdToChannelId.value[key]
    let inv = adminIdToInviteCode.value[key]

    if (channelId === undefined || inv === undefined) {
        const meta = findAdminMetaInTree(adminScopeTree.value, key)
        if (meta) {
            if (channelId === undefined && meta.channel_id !== undefined) {
                channelId = meta.channel_id
            }
            if (inv === undefined) {
                inv = meta.invite_code
            }
        }
    }

    if (channelId !== undefined) {
        baTable.form.items.channel_id = channelId
    }
    baTable.form.items.register_invite_code = inv !== undefined && inv !== null ? inv : ''
}

onMounted(() => {
    loadAdminScopeTree()
})

watch(
    () => baTable.form.items?.admin_id,
    (val) => {
        if (val === undefined || val === null || val === '') return
        onAdminTreeChange(val as any)
    }
)

// 鏍戞暟鎹紓姝ュ姞杞藉畬鎴愬悗锛屾牴鎹凡閫夌鐞嗗憳鍚屾娓犻亾涓庨個璇风爜锛堢紪杈戝洖鏄撅級
watch(
    () => [baTable.form.items?.admin_id, adminScopeTree.value.length] as const,
    () => {
        const id = baTable.form.items?.admin_id
        if (id === undefined || id === null || id === '' || adminScopeTree.value.length === 0) {
            return
        }
        onAdminTreeChange(id as string | number)
    }
)

watch(
    () => baTable.form.items?.risk_flags,
    (v) => {
        syncRiskFromFlags(v)
    }
)

watch(
    riskBits,
    () => {
        if (!baTable.form.items) return
        baTable.form.items.risk_flags = packRiskFlags()
    },
    { deep: true }
)

watch(
    () => baTable.form.operate,
    (op) => {
        if (op === 'Add') {
            syncRiskFromFlags(0)
            if (
                baTable.form.items &&
                (baTable.form.items.admin_id === undefined || baTable.form.items.admin_id === null || baTable.form.items.admin_id === '') &&
                currentAdminId.value !== ''
            ) {
                baTable.form.items.admin_id = currentAdminId.value
                onAdminTreeChange(currentAdminId.value)
            }
        }
    }
)

// 统一 el-tree-select 的 value 为字符串，避免编辑回显不选中
watch(
    () => [baTable.form.operate, baTable.form.items?.id] as const,
    () => {
        const items = baTable.form.items
        if (!items || baTable.form.operate !== 'Edit') {
            return
        }
        if (items.admin_id !== undefined && items.admin_id !== null && items.admin_id !== '') {
            items.admin_id = String(items.admin_id) as any
        }
    }
)

const validatorGameUserPassword = (rule: any, val: string, callback: (error?: Error) => void) => {
    const operate = baTable.form.operate
    const v = typeof val === 'string' ? val.trim() : ''

    if (operate === 'Add') {
        if (!v) return callback(new Error(t('Please input field', { field: t('user.user.password') })))
        if (!regularPassword(v)) return callback(new Error(t('validate.Please enter the correct password')))
        return callback()
    }

    if (!v) return callback()
    if (!regularPassword(v)) return callback(new Error(t('validate.Please enter the correct password')))
    return callback()
}

const rules: Partial<Record<string, FormItemRule[]>> = reactive({
    username: [buildValidatorData({ name: 'required', title: t('user.user.username') })],
    password: [{ validator: validatorGameUserPassword, trigger: 'blur' }],
    phone: [buildValidatorData({ name: 'required', title: t('user.user.phone') })],
    admin_id: [buildValidatorData({ name: 'required', title: t('user.user.admin_affiliation') })],
    create_time: [buildValidatorData({ name: 'date', title: t('user.user.create_time') })],
    update_time: [buildValidatorData({ name: 'date', title: t('user.user.update_time') })],
})
</script>

<style scoped lang="scss">
.game-user-form-tip {
    margin-bottom: 12px;
}
.risk-flag-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 10px;
    align-items: center;
}
.risk-flag-tag {
    cursor: pointer;
    user-select: none;
}
</style>


