<template>
  <div class="app-container">
    <el-card class="permission-card" shadow="never">
      <template #header>
        <div class="card-header">
          <div class="header-left">
            <div class="title-block">
              <span class="main-title">权限配置中心</span>
              <span class="sub-title">设定各角色的系统访问级别与数据可见性</span>
            </div>
          </div>
          <el-button
              type="primary"
              :loading="saving"
              @click="handleSave"
              :disabled="!currentRole"
              size="large"
              icon="Check"
              class="save-btn"
          >
            保存配置
          </el-button>
        </div>
      </template>

      <div class="main-layout">
        <div class="left-panel">
          <div class="panel-header">
            <el-icon><User /></el-icon> 角色列表
          </div>
          <el-scrollbar>
            <ul class="role-list">
              <li
                  v-for="role in roleList"
                  :key="role.value"
                  :class="['role-item', { active: currentRole === role.value }]"
                  @click="handleRoleSelect(role.value)"
              >
                <div class="role-icon">
                  <el-icon v-if="role.value === 'SUPER_ADMIN'"><Avatar /></el-icon>
                  <el-icon v-else><UserFilled /></el-icon>
                </div>
                <div class="role-info">
                  <span class="role-name">{{ role.label }}</span>
                  <span class="role-code">{{ role.value }}</span>
                </div>
                <el-icon v-if="currentRole === role.value" class="arrow-icon"><ArrowRight /></el-icon>
              </li>
            </ul>
          </el-scrollbar>
        </div>

        <div class="right-panel" v-loading="loading">
          <div v-if="!currentRole" class="empty-state">
            <img src="https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg" alt="empty" style="width: 200px; opacity: 0.5;" />
            <p>请在左侧选择一个角色开始配置</p>
          </div>

          <div v-else class="config-content">
            <div class="panel-header">
              <span>权限明细</span>
              <el-tag type="warning" effect="plain" round>当前配置: {{ getRoleLabel(currentRole) }}</el-tag>
            </div>

            <el-table
                :data="tableData"
                row-key="id"
                border
                default-expand-all
                :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
                class="permission-table"
            >
              <el-table-column prop="name" label="页面 / 模块" min-width="200">
                <template #default="{ row }">
                  <span style="font-weight: 500;">{{ row.name }}</span>
                </template>
              </el-table-column>

              <el-table-column label="访问权限" width="150" align="center">
                <template #default="{ row }">
                  <el-checkbox
                      v-model="row.hasRead"
                      @change="(val) => handleReadChange(val, row)"
                      class="custom-checkbox"
                  >
                    <span :class="{ 'text-active': row.hasRead }">可见 (Read)</span>
                  </el-checkbox>
                </template>
              </el-table-column>

              <el-table-column label="操作权限" width="180" align="center">
                <template #default="{ row }">
                  <div v-if="row.operationCode">
                    <el-checkbox
                        v-model="row.hasWrite"
                        :disabled="!row.hasRead"
                        @change="(val) => handleWriteChange(val, row)"
                        class="custom-checkbox"
                    >
                      <span :class="{ 'text-active': row.hasWrite, 'text-disabled': !row.hasRead }">可编辑 (Write)</span>
                    </el-checkbox>
                  </div>
                  <span v-else class="text-gray">-</span>
                </template>
              </el-table-column>

              <el-table-column label="字段级控制 (敏感列)" min-width="300">
                <template #default="{ row }">
                  <div v-if="row.elements && row.elements.length > 0">
                    <el-popover placement="left" :width="300" trigger="click">
                      <template #reference>
                        <el-button link type="primary" :disabled="!row.hasRead">
                          <el-icon style="margin-right: 4px"><Setting /></el-icon>
                          配置 {{ getCheckedCount(row) }}/{{ row.elements.length }} 个字段
                        </el-button>
                      </template>

                      <div class="field-config-box">
                        <div class="field-header">
                          <span>勾选可见字段</span>
                          <el-checkbox
                              v-model="row.checkAllElements"
                              :indeterminate="row.isIndeterminate"
                              @change="(val) => handleCheckAllElements(val, row)"
                              size="small"
                          >全选</el-checkbox>
                        </div>
                        <el-checkbox-group v-model="row.checkedElements" @change="(val) => handleCheckedElementsChange(val, row)">
                          <el-row :gutter="10">
                            <el-col :span="12" v-for="col in row.elements" :key="col.code">
                              <el-checkbox :label="col.code" :title="col.name" style="width: 100%; overflow: hidden; text-overflow: ellipsis;">
                                {{ col.name }}
                              </el-checkbox>
                            </el-col>
                          </el-row>
                        </el-checkbox-group>
                      </div>
                    </el-popover>

                    <span class="preview-tags">
                      <span v-for="code in row.checkedElements.slice(0, 2)" :key="code" class="mini-tag">{{ getElementName(row, code) }}</span>
                      <span v-if="row.checkedElements.length > 2" class="mini-tag">...</span>
                    </span>
                  </div>
                </template>
              </el-table-column>
            </el-table>
          </div>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { User, UserFilled, ArrowRight, Setting, Check, Avatar } from '@element-plus/icons-vue'
import { getAllPermissionTree, getRolePermissions, saveRolePermissions } from '@/api/system/permission'

// --- 类型定义 ---
interface PermissionNode {
  id: number
  name: string
  code: string
  type: string
  children?: PermissionNode[]

  // 前端辅助字段
  hasRead: boolean // 是否勾选了页面
  hasWrite: boolean // 是否勾选了 operation
  operationCode: string | null // 存储 operation 的 code
  elements: any[] // 存储该页面的普通列
  checkedElements: string[] // 已勾选的列code
  checkAllElements: boolean
  isIndeterminate: boolean
}

// --- 状态定义 ---
const loading = ref(false)
const saving = ref(false)
const currentRole = ref('')
const roleList = [
  { label: '超级管理员', value: 'SUPER_ADMIN' },
  { label: '主管', value: 'SUPERVISOR' },
  { label: '财务', value: 'FINANCE' },
  { label: '库管', value: 'WAREHOUSE_MGR' },
  { label: '入库员', value: 'INBOUND' },
  { label: '出库员', value: 'OUTBOUND' },
  { label: '采购员', value: 'PURCHASER' },
  { label: '销售', value: 'SALES' }
]

// 原始树数据
const rawTreeData = ref<any[]>([])
// 表格展示数据 (经过处理)
const tableData = ref<PermissionNode[]>([])

// --- 方法 ---

// 1. 初始化：获取权限树结构
const fetchTree = async () => {
  try {
    const res: any = await getAllPermissionTree()
    if (res.code === 200) {
      rawTreeData.value = res.data
      // 初始化表格结构（此时没有勾选状态）
      tableData.value = transformData(res.data)
    }
  } catch (e) {
    ElMessage.error('加载权限配置失败')
  }
}

// ★ 核心：将后端嵌套的 Tree 数据转换为适合表格展示的结构
// 分离 "页面"、"操作列" 和 "普通列"
const transformData = (nodes: any[]): PermissionNode[] => {
  return nodes.map(node => {
    // 找出所有子节点中的 element
    const allChildren = node.children || []

    // 1. 找操作列 (作为 Write 权限)
    const opNode = allChildren.find((c: any) => c.type === 'element' && (c.code === 'operation' || c.code.endsWith(':operation') || c.code.endsWith('_op')))
    const operationCode = opNode ? opNode.code : null

    // 2. 找普通列 (作为字段权限)
    const columns = allChildren.filter((c: any) => c.type === 'element' && c.code !== 'operation' && !c.code.endsWith('_op') && !c.code.endsWith(':operation'))

    // 3. 找子菜单 (如果有)
    const subMenus = allChildren.filter((c: any) => c.type === 'menu')
    const childrenTransformed = subMenus.length > 0 ? transformData(subMenus) : undefined

    return {
      id: node.id,
      name: node.name,
      code: node.code,
      type: node.type,
      children: childrenTransformed,

      // 状态字段初始化
      hasRead: false,
      hasWrite: false,
      operationCode: operationCode,
      elements: columns,
      checkedElements: [],
      checkAllElements: false,
      isIndeterminate: false
    }
  })
}

// 2. 切换角色：回显权限
const handleRoleSelect = async (roleCode: string) => {
  currentRole.value = roleCode
  loading.value = true

  try {
    // 获取该角色拥有的所有 code
    const res: any = await getRolePermissions(roleCode)
    if (res.code === 200) {
      const perms = new Set([...(res.data.menus || []), ...(res.data.elements || [])])
      // 递归设置表格每一行的状态
      setRowStatus(tableData.value, perms)
    }
  } catch (e) {
    ElMessage.error('获取角色权限失败')
  } finally {
    loading.value = false
  }
}

// 递归回显状态
const setRowStatus = (rows: PermissionNode[], perms: Set<any>) => {
  rows.forEach(row => {
    // 1. 设置可读 (页面Code是否存在)
    row.hasRead = perms.has(row.code)

    // 2. 设置可编辑 (操作列Code是否存在)
    if (row.operationCode) {
      row.hasWrite = perms.has(row.operationCode)
    }

    // 3. 设置已选字段
    if (row.elements && row.elements.length > 0) {
      row.checkedElements = row.elements
          .filter(el => perms.has(el.code))
          .map(el => el.code)

      updateCheckAllStatus(row)
    }

    // 4. 递归子菜单
    if (row.children) {
      setRowStatus(row.children, perms)
    }
  })
}

// --- 交互逻辑 ---

// 当“可读”改变
const handleReadChange = (val: boolean, row: PermissionNode) => {
  // 如果关闭可读，强制关闭可编辑，并清空字段选择
  if (!val) {
    row.hasWrite = false
    // row.checkedElements = [] // 可选：是否同时也清空字段勾选？通常建议保留，方便误触恢复，但这里为了逻辑严谨先不清空，只在保存时过滤
  } else {
    // 如果开启可读，默认全选字段 (提升体验)
    // row.checkedElements = row.elements.map(e => e.code)
    // updateCheckAllStatus(row)
  }

  // 联动子菜单：如果父级关闭，子级是否关闭？通常不强制，但可以做
}

// 当“可编辑”改变
const handleWriteChange = (val: boolean, row: PermissionNode) => {
  // 如果开启编辑，必须开启可读
  if (val && !row.hasRead) {
    row.hasRead = true
  }
}

// 字段全选逻辑
const handleCheckAllElements = (val: boolean, row: PermissionNode) => {
  row.checkedElements = val ? row.elements.map(e => e.code) : []
  row.isIndeterminate = false
}

// 字段单选逻辑
const handleCheckedElementsChange = (val: string[], row: PermissionNode) => {
  updateCheckAllStatus(row)
}

const updateCheckAllStatus = (row: PermissionNode) => {
  const checkedCount = row.checkedElements.length
  row.checkAllElements = checkedCount === row.elements.length && row.elements.length > 0
  row.isIndeterminate = checkedCount > 0 && checkedCount < row.elements.length
}

// --- 保存逻辑 ---
const handleSave = async () => {
  if (!currentRole.value) return

  const permissions: string[] = []

  // 递归收集所有状态为 true 的 code
  const collectPermissions = (rows: PermissionNode[]) => {
    rows.forEach(row => {
      // 1. 页面权限
      if (row.hasRead) {
        permissions.push(row.code)
      }

      // 2. 操作权限 (只有当页面可读时才有效)
      if (row.hasRead && row.hasWrite && row.operationCode) {
        permissions.push(row.operationCode)
      }

      // 3. 字段权限 (只有当页面可读时才有效)
      if (row.hasRead && row.checkedElements.length > 0) {
        permissions.push(...row.checkedElements)
      }

      // 递归
      if (row.children) {
        collectPermissions(row.children)
      }
    })
  }

  collectPermissions(tableData.value)

  saving.value = true
  try {
    const res: any = await saveRolePermissions({
      role_code: currentRole.value,
      permissions: permissions
    })
    if (res.code === 200) {
      ElMessage.success('权限保存成功！')
    } else {
      ElMessage.error(res.msg || '保存失败')
    }
  } catch (e) {
    ElMessage.error('保存失败')
  } finally {
    saving.value = false
  }
}

// --- 辅助 ---
const getRoleLabel = (val: string) => {
  const found = roleList.find(r => r.value === val)
  return found ? found.label : val
}

const getCheckedCount = (row: PermissionNode) => row.checkedElements.length

const getElementName = (row: PermissionNode, code: string) => {
  const found = row.elements.find(e => e.code === code)
  return found ? found.name : code
}

onMounted(() => {
  fetchTree()
})
</script>

<style scoped>
.app-container {
  padding: 15px;
  height: calc(100vh - 84px);
  background-color: #f0f2f5;
}

.permission-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  border: none;
  border-radius: 8px;
}

:deep(.el-card__header) {
  padding: 15px 20px;
  border-bottom: 1px solid #f0f0f0;
}

:deep(.el-card__body) {
  flex: 1;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.title-block {
  display: flex;
  flex-direction: column;
}

.main-title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
}

.sub-title {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}

/* 布局 */
.main-layout {
  display: flex;
  flex: 1;
  height: 100%;
}

/* 左侧样式 */
.left-panel {
  width: 260px;
  background: #fff;
  border-right: 1px solid #f0f0f0;
  display: flex;
  flex-direction: column;
}

.panel-header {
  padding: 15px 20px;
  font-size: 14px;
  font-weight: 600;
  color: #606266;
  background: #fafafa;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  align-items: center;
  gap: 8px;
}

.role-list {
  list-style: none;
  padding: 10px;
  margin: 0;
}

.role-item {
  display: flex;
  align-items: center;
  padding: 12px 15px;
  margin-bottom: 8px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
  color: #606266;
}

.role-item:hover {
  background-color: #f5f7fa;
}

.role-item.active {
  background-color: #e6f7ff;
  color: #1890ff;
  font-weight: 500;
}

.role-icon {
  margin-right: 12px;
  font-size: 18px;
  display: flex;
  align-items: center;
}

.role-info {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.role-name {
  font-size: 14px;
}

.role-code {
  font-size: 11px;
  color: #999;
  margin-top: 2px;
}

.arrow-icon {
  font-size: 14px;
}

/* 右侧样式 */
.right-panel {
  flex: 1;
  background: #fff;
  display: flex;
  flex-direction: column;
  padding: 20px;
  overflow: hidden;
}

.empty-state {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #909399;
  font-size: 14px;
}

.config-content {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.config-content .panel-header {
  background: #fff;
  padding: 0 0 15px 0;
  justify-content: space-between;
}

.permission-table {
  flex: 1;
  overflow: auto;
}

/* 表格内样式 */
.custom-checkbox {
  height: auto;
}

.text-active {
  color: #1890ff;
  font-weight: 500;
}

.text-disabled {
  color: #c0c4cc;
}

.text-gray {
  color: #d9d9d9;
}

/* 字段配置 Popover 样式 */
.field-config-box {
  padding: 5px;
}

.field-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 8px;
  border-bottom: 1px solid #f0f0f0;
  margin-bottom: 10px;
  font-weight: bold;
}

.preview-tags {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  gap: 4px;
}

.mini-tag {
  background: #f5f5f5;
  color: #909399;
  font-size: 11px;
  padding: 1px 4px;
  border-radius: 3px;
}
</style>
