<template>
    <div class="store-page">
        <Breadcrumb />

        <a-card title="用户管理">
            <AppQueryFilter>
            <a-row class="query-row">
                <a-col :flex="'1000px'" class="query-main">
                    <a-form class="queryForm app-query-form" :model="queryData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
                        label-align="left">
                        <a-row :gutter="16">
                            <a-col :span="8">
                                <a-form-item field="user_uuid" label="UUID">
                                    <a-input v-model="queryData.user_uuid" />
                                </a-form-item>
                            </a-col>
                            <a-col :span="8">
                                <a-form-item field="email" label="用户邮箱">
                                    <EmailAutoComplete v-model="queryData.email" allow-clear />
                                </a-form-item>
                            </a-col>
                            <a-col :span="8">
                                <a-form-item field="username" label="用户名">
                                    <a-input v-model="queryData.username" />
                                </a-form-item>
                            </a-col>
                            <a-col :span="8">
                                <a-form-item field="nickname" label="昵称">
                                    <a-input v-model="queryData.nickname" />
                                </a-form-item>
                            </a-col>
                        </a-row>
                    </a-form>
                </a-col>
                <a-divider class="query-divider" style="height: 84px" direction="vertical" />
                <a-col :flex="1" class="app-query-actions">
                    <a-space class="query-actions-space" direction="vertical" :size="18">
                        <a-button type="primary" @click="search">
                            <template #icon>
                                <icon-search />
                            </template>
                            搜索
                        </a-button>
                        <a-button @click="reset">
                            <template #icon>
                                <icon-refresh />
                            </template>
                            重置
                        </a-button>
                    </a-space>
                </a-col>
            </a-row>
            </AppQueryFilter>

            <div class="table-wrap">
            <a-table :data="data" :bordered="false" hoverable class="table" :loading="loading"
                :scroll="{ x: TABLE_SCROLL_X }"
                :columns="tableColumns" :pagination="{
                    showPageSize: true,
                    showJumper: true,
                    showTotal: true,
                    pageSize: pagination.pagesize,
                    current: pagination.current,
                    total: pagination.total
                }" @page-change="handlePageChange" @page-size-change="handlePageSizeChange">
                <template #username="{ record }">
                    <div class="user-cell">
                        <a-avatar :size="35" class="user-cell__avatar">
                            <img :alt="record.username ?? ''"
                                :src="record.avatar ?? 'https://lepao-cloud.xxoo365.top/view.php/25aa126dc406974ff3579a99a2c6501a.png'" />
                        </a-avatar>
                        <span class="user-cell__name">{{ record.username || '-' }}</span>
                    </div>
                </template>
                <template #registTime="{ record }">
                    {{ stramptoTime(record.registTime) }}
                </template>
                <template #lastTime="{ record }">
                    {{ stramptoTime(record.lastTime ?? record.registTime) }}
                </template>
                <template #qq_bind="{ record }">
                    <div v-if="record.qq_social_nickname || record.qq_social_avatar" class="bind-cell">
                        <a-avatar :size="24" class="bind-cell__avatar">
                            <img v-if="record.qq_social_avatar" :alt="record.qq_social_nickname || 'QQ'" :src="record.qq_social_avatar" />
                            <icon-qq v-else />
                        </a-avatar>
                        <span class="bind-cell__text">{{ record.qq_social_nickname || '未获取' }}</span>
                    </div>
                    <span v-else class="muted">未绑定</span>
                </template>
                <template #wx_bind="{ record }">
                    <div v-if="record.wx_social_nickname || record.wx_social_avatar" class="bind-cell">
                        <a-avatar :size="24" class="bind-cell__avatar">
                            <img v-if="record.wx_social_avatar" :alt="record.wx_social_nickname || '微信'" :src="record.wx_social_avatar" />
                            <icon-wechat v-else />
                        </a-avatar>
                        <span class="bind-cell__text">{{ record.wx_social_nickname || '未获取' }}</span>
                    </div>
                    <span v-else class="muted">未绑定</span>
                </template>
                <template #last_login_type="{ record }">
                    <span>{{ formatLastLoginType(record.last_login_type) }}</span>
                </template>
                <template #is_banned_status="{ record }">
                    <a-tag v-if="isBanned(record)" color="red">已封禁</a-tag>
                    <a-tag v-else color="green">正常</a-tag>
                </template>
                <template #optional="{ record }">
                    <a-dropdown :popup-max-height="false" trigger="hover">
                        <a-button>操作 <icon-down /></a-button>
                        <template #content>
                            <a-doption v-if="hasPermission('action.user.changeCount')" @click="changeCount(record)">
                                <icon-edit /> 更改次数
                            </a-doption>
                            <a-doption v-if="hasPermission('action.user.setSendCountAutoApprove')" @click="onSendCountAutoApproveChange(record, !isSendCountAutoApprove(record))">
                                <icon-check-circle /> {{ isSendCountAutoApprove(record) ? '关闭赠送免审' : '开启赠送免审' }}
                            </a-doption>
                            <a-doption v-if="hasPermission('action.user.ban')" @click="onBanChange(record, !isBanned(record))">
                                <icon-minus-circle /> {{ isBanned(record) ? '解除封禁' : '封禁账户' }}
                            </a-doption>
                            <a-doption v-if="hasPermission('action.user.permissionManage')" @click="openPermissionManage(record)">
                                <icon-user /> 权限管理
                            </a-doption>
                            <a-doption v-if="!hasAnyUserOperationPermission" disabled>暂无可用操作</a-doption>
                        </template>
                    </a-dropdown>
                </template>
            </a-table>
            </div>
        </a-card>
    </div>

    <a-modal v-model:visible="visible" title="编辑账号" @cancel="handleCancel" @before-ok="handleBeforeOk" draggable
        :ok-loading="ok_loading" esc-to-close closable>
        <a-form :model="change_lepao_count">
            <a-form-item field="userid" label="用户UUID">
                <a-input v-model="change_lepao_count.userid" disabled />
            </a-form-item>
            <a-form-item field="lepao_count" label="乐跑次数">
                <a-input-number v-model="change_lepao_count.lepao_count" :step="1" />
            </a-form-item>
            <a-form-item field="remark" label="备注">
                <a-textarea v-model="change_lepao_count.remark" no-trim placeholder="可选，不填默认系统调整次数" :max-length="{ length: 255 }"
                    show-word-limit allow-clear />
            </a-form-item>
        </a-form>
    </a-modal>

    <a-modal v-model:visible="permissionVisible" title="权限管理" width="860px" @before-ok="handlePermissionBeforeOk"
        :ok-loading="permissionSaving" :mask-closable="false" draggable esc-to-close closable>
        <a-skeleton animation :loading="permissionLoading">
            <a-skeleton-line :rows="8" />
            <template #content>
            <a-tabs v-model:active-key="permissionTab">
                <a-tab-pane key="user" title="用户权限">
                    <a-space direction="vertical" fill>
                        <a-alert>
                            正在配置用户 {{ permissionUser?.username || permissionUser?.uuid || '-' }} 的权限。乐跑账号、赠送次数、发起工单等基础操作默认全员开放，取消勾选即可单独关闭；管理端等高级权限需额外勾选。旧角色继承权限会展示在下方，但不会随本窗口保存而改变。
                        </a-alert>
                        <a-radio-group v-model="permissionCategory" type="button">
                            <a-radio value="">全部</a-radio>
                            <a-radio value="page">页面</a-radio>
                            <a-radio value="action">操作</a-radio>
                        </a-radio-group>
                        <a-checkbox-group v-model="selectedPermissionCodes" class="permission-list">
                            <a-grid :cols="2" :col-gap="12" :row-gap="12">
                                <a-grid-item v-for="item in filteredPermissionPoints" :key="item.code">
                                    <a-card size="small" :bordered="true" :class="{ 'permission-card-basic': isBasicPermission(item.code) }">
                                        <a-checkbox :value="item.code">
                                            <div class="permission-title">
                                                {{ item.name }}
                                                <a-tag v-if="isBasicPermission(item.code)" size="small" color="arcoblue">默认开放</a-tag>
                                            </div>
                                            <div class="permission-code">{{ item.code }}</div>
                                            <div v-if="item.remark" class="permission-remark">{{ item.remark }}</div>
                                        </a-checkbox>
                                    </a-card>
                                </a-grid-item>
                            </a-grid>
                        </a-checkbox-group>
                        <div>
                            <div class="permission-section-title">当前生效权限</div>
                            <a-space wrap>
                                <a-tag v-for="code in effectivePermissionCodes" :key="code">{{ code }}</a-tag>
                                <span v-if="effectivePermissionCodes.length === 0" class="muted">暂无</span>
                            </a-space>
                        </div>
                    </a-space>
                </a-tab-pane>
                <a-tab-pane key="resource" title="权限规则">
                    <a-alert style="margin-bottom: 12px;">
                        这里配置页面、操作或接口需要哪些权限。关闭规则或清空权限后，该资源默认不需要权限。
                    </a-alert>
                    <div class="permission-resource-list">
                        <a-card v-for="rule in permissionResources" :key="rule.id" size="small" class="permission-resource-card">
                            <a-space direction="vertical" fill>
                                <a-row align="center">
                                    <a-col :flex="1">
                                        <div class="permission-title">{{ formatResourceRule(rule) }}</div>
                                        <div class="permission-code">{{ rule.resource_type }}：{{ rule.resource_key }}</div>
                                    </a-col>
                                    <a-col>
                                        <a-switch v-model="rule.enabled" :checked-value="1" :unchecked-value="0" />
                                    </a-col>
                                </a-row>
                                <a-select v-model="rule.required_codes" multiple allow-search allow-clear placeholder="请选择该资源需要的权限点">
                                    <a-option v-for="item in permissionPoints" :key="item.code" :value="item.code">
                                        {{ item.name }}（{{ item.code }}）
                                    </a-option>
                                </a-select>
                                <a-button size="small" type="primary" :loading="resourceSavingId === rule.id" @click="saveResourceRule(rule)">
                                    保存规则
                                </a-button>
                            </a-space>
                        </a-card>
                    </div>
                </a-tab-pane>
            </a-tabs>
            </template>
        </a-skeleton>
    </a-modal>
</template>

<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { useResponsiveTable } from '@/hooks/useResponsiveTable'
import { adminGetUserList, adminChangeLepaoCount, adminSetSendCountAutoApprove, adminSetUserBan } from '@/api/user'
import { getPermissionPoints, getPermissionResources, getUserPermissions, setUserPermissions, updatePermissionResource } from '@/api/permission'
import { Notification, Message, Modal } from '@arco-design/web-vue'
import {
    buildSelectedPermissionCodes,
    extractDeniedBasicPermissionCodes,
    filterSavablePermissionCodes,
    hasPermission,
    isBasicPermission
} from '@/utils/permission'

const visible = ref(false)
const ok_loading = ref(false)
const change_lepao_count = reactive({
    userid: '',
    lepao_count: 0,
    remark: ''
})

const queryData = reactive({
    user_uuid: '',
    email: '',
    username: '',
    nickname: '',
})

const pagination = reactive({
    total: 0,
    current: 1, // 默认从第1页开始
    pagesize: 20
})

const loading = ref(false)
const data = ref([])
const whitelistLoadingUuid = ref('')
const banLoadingUuid = ref('')
const permissionVisible = ref(false)
const permissionLoading = ref(false)
const permissionSaving = ref(false)
const permissionCategory = ref('')
const permissionTab = ref('user')
const permissionUser = ref(null)
const permissionPoints = ref([])
const permissionResources = ref([])
const selectedPermissionCodes = ref([])
const effectivePermissionCodes = ref([])
const resourceSavingId = ref(0)

const hasAnyUserOperationPermission = computed(() => {
    return [
        'action.user.changeCount',
        'action.user.setSendCountAutoApprove',
        'action.user.ban',
        'action.user.permissionManage'
    ].some(code => hasPermission(code))
})

const filteredPermissionPoints = computed(() => {
    if (!permissionCategory.value) return permissionPoints.value
    return permissionPoints.value.filter(item => item.category === permissionCategory.value)
})

const isSendCountAutoApprove = (record) => Number(record?.send_count_auto_approve) === 1
const isBanned = (record) => Number(record?.is_banned) === 1

const onSendCountAutoApproveChange = async (record, checked) => {
    if (!record?.uuid || whitelistLoadingUuid.value) return
    const next = checked === true ? 1 : 0
    whitelistLoadingUuid.value = record.uuid
    try {
        const res = await adminSetSendCountAutoApprove({
            userid: record.uuid,
            send_count_auto_approve: next
        })
        if (!res || res.code !== 0) {
            Notification.error({
                title: '保存失败',
                content: res?.msg ?? '请稍后再试'
            })
            return
        }
        record.send_count_auto_approve = next
        Message.success(next ? '已加入赠送免审白名单' : '已关闭赠送免审')
    } catch (error) {
        Notification.error({
            title: '保存失败',
            content: error.message || '请稍后再试'
        })
    } finally {
        whitelistLoadingUuid.value = ''
    }
}

const setUserBan = async (record, next) => {
    banLoadingUuid.value = record.uuid
    try {
        const res = await adminSetUserBan({
            userid: record.uuid,
            is_banned: next
        })
        if (!res || res.code !== 0) {
            Notification.error({
                title: '操作失败',
                content: res?.msg ?? '请稍后再试'
            })
            return
        }
        record.is_banned = next
        Message.success(next ? '已封禁该用户' : '已解除封禁')
    } catch (error) {
        Notification.error({
            title: '操作失败',
            content: error.message || '请稍后再试'
        })
    } finally {
        banLoadingUuid.value = ''
    }
}

const onBanChange = async (record, checked) => {
    if (!record?.uuid || banLoadingUuid.value) return
    const next = checked === true ? 1 : 0
    if (next === 1) {
        Modal.confirm({
            title: '确认封禁',
            content: `确定封禁用户「${record.username || record.uuid}」？封禁后该用户将立即下线且无法登录。`,
            onOk: async () => {
                await setUserBan(record, next)
            }
        })
        return
    }
    await setUserBan(record, 0)
}

const openPermissionManage = async (record) => {
    if (!record?.uuid) return
    permissionUser.value = record
    permissionVisible.value = true
    permissionLoading.value = true
    permissionTab.value = 'user'
    permissionCategory.value = ''
    selectedPermissionCodes.value = []
    effectivePermissionCodes.value = []

    try {
        const [pointRes, userRes, resourceRes] = await Promise.all([
            getPermissionPoints(),
            getUserPermissions({ userid: record.uuid }),
            getPermissionResources()
        ])

        if (!pointRes || pointRes.code !== 0)
            throw new Error(pointRes?.msg || '获取权限点失败')
        if (!userRes || userRes.code !== 0)
            throw new Error(userRes?.msg || '获取用户权限失败')
        if (!resourceRes || resourceRes.code !== 0)
            throw new Error(resourceRes?.msg || '获取权限规则失败')

        permissionPoints.value = pointRes.data || []
        permissionResources.value = (resourceRes.data || []).map(item => ({
            ...item,
            enabled: Number(item.enabled) === 0 ? 0 : 1,
            required_codes: item.required_codes || []
        }))
        selectedPermissionCodes.value = buildSelectedPermissionCodes({
            directPermissionCodes: userRes.data?.directPermissionCodes,
            deniedBasicPermissionCodes: userRes.data?.deniedBasicPermissionCodes
        })
        effectivePermissionCodes.value = userRes.data?.effectivePermissionCodes || []
    } catch (error) {
        Notification.error({
            title: '获取权限失败',
            content: error.message || '请稍后再试'
        })
        permissionVisible.value = false
    } finally {
        permissionLoading.value = false
    }
}

const formatResourceRule = (rule) => {
    if (rule.resource_type === 'page') return `页面：${rule.resource_key}`
    if (rule.resource_type === 'action') return `操作：${rule.resource_key}`
    if (rule.resource_type === 'api') return `接口：${rule.api_method || ''} ${rule.api_path || rule.resource_key}`
    return rule.resource_key
}

const saveResourceRule = async (rule) => {
    resourceSavingId.value = rule.id
    try {
        const res = await updatePermissionResource({
            id: rule.id,
            enabled: rule.enabled,
            required_codes: rule.required_codes || []
        })
        if (!res || res.code !== 0) {
            Notification.error({
                title: '保存权限规则失败',
                content: res?.msg ?? '请稍后再试'
            })
            return
        }
        Message.success('权限规则已保存')
    } catch (error) {
        Notification.error({
            title: '保存权限规则失败',
            content: error.message || '请稍后再试'
        })
    } finally {
        resourceSavingId.value = 0
    }
}

const handlePermissionBeforeOk = async (done) => {
    if (!permissionUser.value?.uuid) return false
    permissionSaving.value = true
    try {
        const res = await setUserPermissions({
            userid: permissionUser.value.uuid,
            permissionCodes: filterSavablePermissionCodes(selectedPermissionCodes.value),
            deniedBasicPermissionCodes: extractDeniedBasicPermissionCodes(selectedPermissionCodes.value)
        })

        if (!res || res.code !== 0) {
            Notification.error({
                title: '保存权限失败',
                content: res?.msg ?? '请稍后再试'
            })
            return false
        }

        effectivePermissionCodes.value = res.data?.effectivePermissionCodes || []
        Message.success('权限已保存')
        done()
        return true
    } catch (error) {
        Notification.error({
            title: '保存权限失败',
            content: error.message || '请稍后再试'
        })
        return false
    } finally {
        permissionSaving.value = false
    }
}

const { useTableColumns } = useResponsiveTable()

/** 列宽合计，移动端横向滚动查看全部字段 */
const TABLE_SCROLL_X = 1650

const columnDefs = [
    {
        title: 'UUID',
        dataIndex: 'uuid',
        width: 200,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '用户名',
        slotName: 'username',
        width: 180,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '邮箱',
        dataIndex: 'email',
        width: 200,
        ellipsis: true,
        tooltip: true
    },
    {
        title: 'QQ 绑定',
        slotName: 'qq_bind',
        width: 160,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '微信绑定',
        slotName: 'wx_bind',
        width: 160,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '登录方式',
        slotName: 'last_login_type',
        width: 120,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '注册时间',
        slotName: 'registTime',
        width: 170,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '上次登录时间',
        slotName: 'lastTime',
        width: 170,
        ellipsis: true,
        tooltip: true
    },
    {
        title: '剩余乐跑次数',
        dataIndex: 'lepao_count',
        width: 120
    },
    {
        title: '账号状态',
        slotName: 'is_banned_status',
        width: 100
    },
    {
        title: '操作',
        slotName: 'optional',
        width: 120,
        align: 'center',
        fixed: 'right'
    }
]

const tableColumns = useTableColumns(columnDefs)

const search = () => {
    pagination.current = 1
    getUserList()
}

const reset = () => {
    queryData.user_uuid = ''
    queryData.email = ''
    queryData.username = ''
    queryData.nickname = ''
    getUserList()
}

const getUserList = async () => {
    try {
        loading.value = true
        const reqData = {
            ...queryData,
            pagesize: pagination.pagesize,
            current: pagination.current
        }
        const res = await adminGetUserList(reqData)
        if (!res || res.code !== 0)
            return Notification.error({
                title: '获取路径数据失败！',
                content: res?.msg ?? '请稍后再试'
            })

        data.value = res.data
        pagination.total = res.pagination.total
    } catch (error) {
        Notification.error({
            title: '获取路径数据失败！',
            content: error.message || '请稍后再试'
        })
    } finally {
        loading.value = false
    }
}

const changeCount = (item) => {
    if (item) {
        change_lepao_count.userid = item.uuid
        change_lepao_count.lepao_count = item.lepao_count
        change_lepao_count.remark = ''
    }
    else return
    visible.value = true
}

const handleBeforeOk = async (done) => {
    try {
        ok_loading.value = true

        let data = {
            ...change_lepao_count
        }

        const res = await adminChangeLepaoCount(data)
        if (!res || res.code !== 0) {
            Notification.error({
                title: '保存乐跑账号失败！',
                content: res?.msg ?? '请稍后再试'
            })
            return false
        }

        Message.success('保存成功！')
        done()
        getUserList()
    } catch (error) {
        Notification.error({
            title: '保存乐跑账号失败！',
            content: error.message || '请稍后再试'
        })
        return false
    } finally {
        ok_loading.value = false
    }
}

const handleCancel = () => {
    visible.value = false;
}

// 分页 - 页码变化
const handlePageChange = (page) => {
    pagination.current = page
    getUserList()
}

// 分页 - 每页条数变化
const handlePageSizeChange = (size) => {
    pagination.pagesize = size
    pagination.current = 1 // 页大小变化后回到第一页
    getUserList()
}

onMounted(() => {
    getUserList()
})

const stramptoTime = (time) => {
    return new Date(time).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })
}

/** login_history.type：最近一次登录方式 */
const formatLastLoginType = (type) => {
    if (type === null || type === undefined || type === '') return '无记录'
    const t = String(type).toLowerCase()
    if (t === 'password') return '账号密码'
    if (t === 'qq') return 'QQ'
    if (t === 'wx') return '微信'
    return type
}

</script>

<style scoped>
.query-row {
    margin-bottom: 10px;
}

.query-main {
    min-width: 0;
}

.query-actions-space {
    width: 100%;
}

.table-wrap {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin-top: 15px;
}

.table {
    margin-top: 0;
    min-width: 100%;
}

.table :deep(.arco-table-td),
.table :deep(.arco-table-th) {
    overflow: hidden;
}

.user-cell {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: 100%;
    min-width: 0;
    vertical-align: middle;
}

.user-cell__avatar {
    flex-shrink: 0;
}

.user-cell__name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bind-cell {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    min-width: 0;
    vertical-align: middle;
}

.bind-cell__avatar {
    flex-shrink: 0;
}

.bind-cell__text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.muted {
    color: var(--color-text-3);
}

.permission-list {
    width: 100%;
    max-height: 420px;
    overflow-y: auto;
}

.permission-title {
    font-weight: 500;
    color: var(--color-text-1);
}

.permission-code,
.permission-remark {
    margin-top: 4px;
    color: var(--color-text-3);
    font-size: 12px;
}

.permission-section-title {
    margin-bottom: 8px;
    font-weight: 500;
}

.permission-card-basic {
    opacity: 0.85;
}

.permission-resource-list {
    max-height: 480px;
    overflow-y: auto;
}

.permission-resource-card + .permission-resource-card {
    margin-top: 12px;
}

@media (max-width: 768px) {
    .query-row {
        display: block;
    }

    .query-divider {
        display: none;
    }

    .query-actions-space {
        margin-top: 4px;
        flex-direction: row !important;
        gap: 10px !important;
    }

    .query-actions-space :deep(.arco-btn) {
        flex: 1;
    }
}
</style>