<!--
=============================================================================
企微IT智能服务台 — 角色管理页
=============================================================================
说明：管理用户角色分配和角色映射规则
  - 角色卡片：展示 3 个预置角色（用户/坐席/管理员）及用户数量
  - 用户角色分配：手动为用户分配/撤销角色
  - 映射规则：配置企微标签/eHR 岗位自动映射到角色
-->
<template>
  <div class="roles-page">
    <!-- 页面标题 -->
    <div class="page-header">
      <div>
        <div class="page-title">角色管理</div>
        <div class="page-desc">管理系统角色定义、用户角色分配和自动映射规则</div>
      </div>
    </div>

    <!-- 加载状态 -->
    <div v-if="loading" class="loading-state">
      <el-skeleton :rows="8" animated />
    </div>

    <template v-else>
      <!-- ============================================================ -->
      <!-- 角色卡片 -->
      <!-- ============================================================ -->
      <div class="section-title">角色概览</div>
      <div class="role-cards">
        <div
          v-for="role in roles"
          :key="role.id"
          class="role-card"
          :class="{ 'role-card--default': role.is_default }"
        >
          <div class="role-card-header">
            <div class="role-card-icon" :style="{ background: getRoleIconBg(role.name), color: getRoleIconColor(role.name) }">
              <el-icon :size="20">
                <User v-if="role.name === 'user'" />
                <Headset v-else-if="role.name === 'agent'" />
                <UserFilled v-else />
              </el-icon>
            </div>
            <div class="role-card-info">
              <div class="role-card-name">{{ role.display_name }}</div>
              <div class="role-card-id">{{ role.name }}</div>
            </div>
            <el-tag v-if="role.is_default" type="info" size="small">默认</el-tag>
          </div>

          <div class="role-card-stats">
            <div class="stat-item">
              <span class="stat-value">{{ role.user_count ?? 0 }}</span>
              <span class="stat-label">关联用户</span>
            </div>
            <div class="stat-item">
              <span class="stat-value">{{ role.permissions.length }}</span>
              <span class="stat-label">权限数</span>
            </div>
          </div>

          <div v-if="role.description" class="role-card-desc">{{ role.description }}</div>

          <div class="role-card-perms">
            <el-tag
              v-for="perm in role.permissions.slice(0, 6)"
              :key="perm"
              size="small"
              type="info"
              class="perm-tag"
            >
              {{ perm }}
            </el-tag>
            <el-tag v-if="role.permissions.length > 6" size="small" type="info" class="perm-tag">
              +{{ role.permissions.length - 6 }}
            </el-tag>
          </div>
        </div>
      </div>

      <!-- ============================================================ -->
      <!-- 用户角色分配 -->
      <!-- ============================================================ -->
      <div class="section-header">
        <div class="section-title">用户角色分配</div>
        <el-button type="primary" size="small" @click="showAssignDialog">
          <el-icon><Plus /></el-icon>
          分配角色
        </el-button>
      </div>

      <div class="data-table-wrapper">
        <el-table
          :data="filteredUserRoles"
          stripe
          size="small"
          empty-text="暂无用户角色记录"
        >
          <el-table-column prop="employee_id" label="员工 ID" min-width="140" />
          <el-table-column prop="role_display_name" label="角色" min-width="100">
            <template #default="{ row }">
              <el-tag :type="getRoleTagType(row.role_name)" size="small">
                {{ row.role_display_name }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="source" label="来源" min-width="100">
            <template #default="{ row }">
              <span class="source-badge" :class="'source-' + row.source">
                {{ ROLE_SOURCE_LABELS[row.source as UserRoleSource] || row.source }}
              </span>
            </template>
          </el-table-column>
          <el-table-column prop="assigned_by" label="分配者" min-width="100">
            <template #default="{ row }">
              {{ row.assigned_by || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="assigned_at" label="分配时间" min-width="160">
            <template #default="{ row }">
              {{ formatTime(row.assigned_at) }}
            </template>
          </el-table-column>
          <el-table-column prop="expires_at" label="过期时间" min-width="160">
            <template #default="{ row }">
              <span v-if="row.expires_at">{{ formatTime(row.expires_at) }}</span>
              <span v-else class="text-muted">永不过期</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="100" fixed="right">
            <template #default="{ row }">
              <el-button
                type="danger"
                size="small"
                link
                :disabled="isDefaultRole(row.role_name)"
                @click="handleRevoke(row)"
              >
                撤销
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <!-- ============================================================ -->
      <!-- 角色映射规则 -->
      <!-- ============================================================ -->
      <div class="section-header">
        <div class="section-title">自动映射规则</div>
        <el-button type="primary" size="small" @click="showCreateRuleDialog">
          <el-icon><Plus /></el-icon>
          新建规则
        </el-button>
      </div>

      <div class="data-table-wrapper">
        <el-table
          :data="mappingRules"
          stripe
          size="small"
          empty-text="暂无映射规则"
        >
          <el-table-column prop="role_name" label="目标角色" min-width="100">
            <template #default="{ row }">
              <el-tag :type="getRoleTagType(row.role_name)" size="small">
                {{ row.role_name }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="source_type" label="来源类型" min-width="120">
            <template #default="{ row }">
              {{ MAPPING_SOURCE_LABELS[row.source_type as MappingSourceSource] || row.source_type }}
            </template>
          </el-table-column>
          <el-table-column prop="source_value" label="匹配值" min-width="160" />
          <el-table-column prop="priority" label="优先级" min-width="80" />
          <el-table-column prop="is_active" label="状态" min-width="80">
            <template #default="{ row }">
              <el-tag :type="row.is_active ? 'success' : 'info'" size="small">
                {{ row.is_active ? '启用' : '禁用' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="created_at" label="创建时间" min-width="160">
            <template #default="{ row }">
              {{ formatTime(row.created_at) }}
            </template>
          </el-table-column>
          <el-table-column label="操作" width="100" fixed="right">
            <template #default="{ row }">
              <el-button
                type="danger"
                size="small"
                link
                @click="handleDeleteRule(row)"
              >
                删除
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </template>

    <!-- ============================================================ -->
    <!-- 分配角色对话框 -->
    <!-- ============================================================ -->
    <el-dialog
      v-model="assignDialogVisible"
      title="分配角色"
      width="440px"
      destroy-on-close
    >
      <el-form label-position="top">
        <el-form-item label="员工 ID（企微 UserID）">
          <el-input
            v-model="assignForm.employee_id"
            placeholder="输入企微 UserID"
          />
        </el-form-item>
        <el-form-item label="目标角色">
          <el-select v-model="assignForm.role_name" placeholder="选择角色" style="width: 100%">
            <el-option
              v-for="role in roles"
              :key="role.name"
              :label="role.display_name + ' (' + role.name + ')'"
              :value="role.name"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="分配原因（可选）">
          <el-input
            v-model="assignForm.reason"
            type="textarea"
            :rows="2"
            placeholder="说明分配原因"
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="assignDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="assigning" @click="handleAssign">
          {{ assigning ? '分配中...' : '确认分配' }}
        </el-button>
      </template>
    </el-dialog>

    <!-- ============================================================ -->
    <!-- 撤销角色确认对话框 -->
    <!-- ============================================================ -->
    <el-dialog
      v-model="revokeDialogVisible"
      title="撤销角色"
      width="440px"
      destroy-on-close
    >
      <div v-if="revokingUserRole" class="revoke-info">
        <p>确认撤销以下角色分配？</p>
        <div class="revoke-detail">
          <div><strong>员工：</strong>{{ revokingUserRole.employee_id }}</div>
          <div><strong>角色：</strong>{{ revokingUserRole.role_display_name }} ({{ revokingUserRole.role_name }})</div>
          <div><strong>来源：</strong>{{ ROLE_SOURCE_LABELS[revokingUserRole.source as UserRoleSource] || revokingUserRole.source }}</div>
        </div>
      </div>
      <el-form label-position="top" style="margin-top: 16px;">
        <el-form-item label="撤销原因（可选）">
          <el-input
            v-model="revokeForm.reason"
            type="textarea"
            :rows="2"
            placeholder="说明撤销原因"
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="revokeDialogVisible = false">取消</el-button>
        <el-button type="danger" :loading="revoking" @click="handleRevokeConfirm">
          {{ revoking ? '撤销中...' : '确认撤销' }}
        </el-button>
      </template>
    </el-dialog>

    <!-- ============================================================ -->
    <!-- 新建映射规则对话框 -->
    <!-- ============================================================ -->
    <el-dialog
      v-model="createRuleDialogVisible"
      title="新建映射规则"
      width="480px"
      destroy-on-close
    >
      <el-form label-position="top">
        <el-form-item label="目标角色">
          <el-select v-model="ruleForm.role_name" placeholder="选择角色" style="width: 100%">
            <el-option
              v-for="role in roles"
              :key="role.name"
              :label="role.display_name + ' (' + role.name + ')'"
              :value="role.name"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="来源类型">
          <el-select v-model="ruleForm.source_type" placeholder="选择来源类型" style="width: 100%">
            <el-option label="企微标签" value="wecom_tag" />
            <el-option label="eHR 岗位" value="ehr_position" />
          </el-select>
        </el-form-item>
        <el-form-item label="匹配值">
          <el-input
            v-model="ruleForm.source_value"
            :placeholder="ruleForm.source_type === 'wecom_tag' ? '企微标签名，如 IT坐席' : '岗位关键词，如 IT支持'"
          />
          <div class="form-hint">
            {{ ruleForm.source_type === 'wecom_tag'
              ? '用户拥有此企微标签时，自动获得目标角色'
              : '用户 eHR 岗位包含此关键词时，自动获得目标角色'
            }}
          </div>
        </el-form-item>
        <el-form-item label="优先级（0-100）">
          <el-input-number v-model="ruleForm.priority" :min="0" :max="100" :step="10" />
          <div class="form-hint">数值越大优先级越高，同一来源取最高优先级角色</div>
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="createRuleDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="creatingRule" @click="handleCreateRule">
          {{ creatingRule ? '创建中...' : '创建规则' }}
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
// ==========================================================================
// 依赖导入
// ==========================================================================
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, User, Headset, UserFilled } from '@element-plus/icons-vue'
import {
  getRoles,
  assignRole,
  revokeRole,
  getRoleMappingRules,
  createRoleMappingRule,
  deleteRoleMappingRule,
} from '@/api/admin'
import type {
  Role,
  UserRole,
  UserRoleSource,
  RoleMappingRule,
  MappingSourceSource,
} from '@/types'
import { ROLE_SOURCE_LABELS, MAPPING_SOURCE_LABELS } from '@/types'

// ==========================================================================
// 状态
// ==========================================================================
const loading = ref<boolean>(false)
const roles = ref<Role[]>([])
const userRoles = ref<UserRole[]>([])
const mappingRules = ref<RoleMappingRule[]>([])

// ==========================================================================
// 分配角色
// ==========================================================================
const assignDialogVisible = ref<boolean>(false)
const assigning = ref<boolean>(false)
const assignForm = reactive({
  employee_id: '',
  role_name: 'agent',
  reason: '',
})

// ==========================================================================
// 撤销角色
// ==========================================================================
const revokeDialogVisible = ref<boolean>(false)
const revoking = ref<boolean>(false)
const revokingUserRole = ref<UserRole | null>(null)
const revokeForm = reactive({
  reason: '',
})

// ==========================================================================
// 新建映射规则
// ==========================================================================
const createRuleDialogVisible = ref<boolean>(false)
const creatingRule = ref<boolean>(false)
const ruleForm = reactive({
  role_name: 'agent',
  source_type: 'wecom_tag' as MappingSourceSource,
  source_value: '',
  priority: 10,
})

// ==========================================================================
// 初始化
// ==========================================================================
onMounted(async () => {
  loading.value = true
  try {
    const [rolesRes, rulesRes] = await Promise.all([
      getRoles(),
      getRoleMappingRules(),
    ])
    roles.value = rolesRes.data.data
    mappingRules.value = rulesRes.data.data
  } catch {
    // 使用默认 demo 数据
    roles.value = getDefaultRoles()
    mappingRules.value = getDefaultMappingRules()
  } finally {
    loading.value = false
  }
})

// ==========================================================================
// 默认数据（API 不可用时的 fallback）
// ==========================================================================
function getDefaultRoles(): Role[] {
  return [
    {
      id: '1', name: 'user', display_name: '用户',
      description: '普通用户，通过企微 H5 端提交问题',
      permissions: ['ticket.create', 'ticket.view_own', 'message.send'],
      is_default: true, user_count: 120,
      created_at: '2026-06-12T00:00:00', updated_at: '2026-06-12T00:00:00',
    },
    {
      id: '2', name: 'agent', display_name: '坐席',
      description: 'IT 支持坐席，处理用户问题',
      permissions: ['ticket.create', 'ticket.view_all', 'ticket.assign', 'ticket.resolve', 'conversation.manage', 'quick_reply.use'],
      is_default: false, user_count: 8,
      created_at: '2026-06-12T00:00:00', updated_at: '2026-06-12T00:00:00',
    },
    {
      id: '3', name: 'admin', display_name: '管理员',
      description: '系统管理员，拥有全部管理权限',
      permissions: ['ticket.create', 'ticket.view_all', 'ticket.assign', 'ticket.resolve', 'conversation.manage', 'quick_reply.manage', 'system.config', 'agent.manage', 'role.manage'],
      is_default: false, user_count: 2,
      created_at: '2026-06-12T00:00:00', updated_at: '2026-06-12T00:00:00',
    },
  ]
}

function getDefaultMappingRules(): RoleMappingRule[] {
  return [
    {
      id: '1', role_id: '2', role_name: 'agent', source_type: 'wecom_tag',
      source_value: 'IT坐席', priority: 10, is_active: true,
      created_at: '2026-06-12T00:00:00',
    },
    {
      id: '2', role_id: '2', role_name: 'agent', source_type: 'ehr_position',
      source_value: 'IT支持', priority: 5, is_active: true,
      created_at: '2026-06-12T00:00:00',
    },
    {
      id: '3', role_id: '2', role_name: 'agent', source_type: 'ehr_position',
      source_value: 'IT运维', priority: 5, is_active: true,
      created_at: '2026-06-12T00:00:00',
    },
    {
      id: '4', role_id: '2', role_name: 'agent', source_type: 'ehr_position',
      source_value: '技术支持', priority: 3, is_active: true,
      created_at: '2026-06-12T00:00:00',
    },
  ]
}

// ==========================================================================
// 用户角色列表（从角色卡片点击可筛选，目前显示全部）
// ==========================================================================
const filteredUserRoles = computed(() => userRoles.value)

// ==========================================================================
// 工具函数
// ==========================================================================

/** 格式化时间 */
function formatTime(iso: string): string {
  if (!iso) return '-'
  const d = new Date(iso)
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

/** 角色标签颜色 */
function getRoleTagType(name: string): 'success' | 'warning' | 'danger' | 'info' {
  const map: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
    user: 'info',
    agent: 'success',
    admin: 'danger',
  }
  return map[name] || 'info'
}

/** 角色图标背景色 */
function getRoleIconBg(name: string): string {
  const map: Record<string, string> = {
    user: 'var(--bg-tertiary)',
    agent: 'var(--success-bg)',
    admin: 'var(--danger-bg)',
  }
  return map[name] || 'var(--bg-tertiary)'
}

/** 角色图标颜色 */
function getRoleIconColor(name: string): string {
  const map: Record<string, string> = {
    user: 'var(--text-muted)',
    agent: 'var(--success)',
    admin: 'var(--danger)',
  }
  return map[name] || 'var(--text-muted)'
}

/** 是否默认角色（默认角色不允许撤销） */
function isDefaultRole(roleName: string): boolean {
  return roles.value.some(r => r.name === roleName && r.is_default)
}

// ==========================================================================
// 操作处理
// ==========================================================================

/** 打开分配角色对话框 */
function showAssignDialog(): void {
  assignForm.employee_id = ''
  assignForm.role_name = 'agent'
  assignForm.reason = ''
  assignDialogVisible.value = true
}

/** 提交分配角色 */
async function handleAssign(): Promise<void> {
  if (!assignForm.employee_id.trim()) {
    ElMessage.warning('请输入员工 ID')
    return
  }
  if (!assignForm.role_name) {
    ElMessage.warning('请选择目标角色')
    return
  }

  assigning.value = true
  try {
    await assignRole({
      employee_id: assignForm.employee_id.trim(),
      role_name: assignForm.role_name,
      reason: assignForm.reason || undefined,
    })
    ElMessage.success('角色分配成功')
    assignDialogVisible.value = false
    // 刷新数据
    await loadData()
  } catch {
    ElMessage.error('分配失败，请检查员工 ID 是否正确')
  } finally {
    assigning.value = false
  }
}

/** 打开撤销角色确认 */
function handleRevoke(userRole: UserRole): void {
  revokingUserRole.value = userRole
  revokeForm.reason = ''
  revokeDialogVisible.value = true
}

/** 确认撤销角色 */
async function handleRevokeConfirm(): Promise<void> {
  if (!revokingUserRole.value) return

  revoking.value = true
  try {
    await revokeRole({
      employee_id: revokingUserRole.value.employee_id,
      role_name: revokingUserRole.value.role_name,
      reason: revokeForm.reason || undefined,
    })
    ElMessage.success('角色撤销成功')
    revokeDialogVisible.value = false
    await loadData()
  } catch {
    ElMessage.error('撤销失败')
  } finally {
    revoking.value = false
  }
}

/** 打开新建映射规则对话框 */
function showCreateRuleDialog(): void {
  ruleForm.role_name = 'agent'
  ruleForm.source_type = 'wecom_tag'
  ruleForm.source_value = ''
  ruleForm.priority = 10
  createRuleDialogVisible.value = true
}

/** 提交创建映射规则 */
async function handleCreateRule(): Promise<void> {
  if (!ruleForm.source_value.trim()) {
    ElMessage.warning('请输入匹配值')
    return
  }

  creatingRule.value = true
  try {
    await createRoleMappingRule({
      role_name: ruleForm.role_name,
      source_type: ruleForm.source_type,
      source_value: ruleForm.source_value.trim(),
      priority: ruleForm.priority,
    })
    ElMessage.success('映射规则创建成功')
    createRuleDialogVisible.value = false
    await loadData()
  } catch {
    ElMessage.error('创建失败，可能已存在相同规则')
  } finally {
    creatingRule.value = false
  }
}

/** 删除映射规则 */
async function handleDeleteRule(rule: RoleMappingRule): Promise<void> {
  try {
    await ElMessageBox.confirm(
      `确认删除映射规则：${MAPPING_SOURCE_LABELS[rule.source_type]} = "${rule.source_value}" → ${rule.role_name}？`,
      '删除确认',
      { type: 'warning' }
    )
  } catch {
    return // 用户取消
  }

  try {
    await deleteRoleMappingRule(rule.id)
    ElMessage.success('映射规则已删除')
    await loadData()
  } catch {
    ElMessage.error('删除失败')
  }
}

/** 刷新全部数据 */
async function loadData(): Promise<void> {
  try {
    const [rolesRes, rulesRes] = await Promise.all([
      getRoles(),
      getRoleMappingRules(),
    ])
    roles.value = rolesRes.data.data
    mappingRules.value = rulesRes.data.data
  } catch {
    // 静默失败，保留现有数据
  }
}
</script>

<style scoped>
.roles-page {
  /* 页面容器 */
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 24px;
}

.page-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 4px;
}

.page-desc {
  font-size: 13px;
  color: var(--text-muted);
}

.loading-state {
  padding: 24px 0;
}

/* 区块标题 */
.section-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 12px;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 28px 0 12px;
}

/* 角色卡片网格 */
.role-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
  margin-bottom: 8px;
}

.role-card {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px;
  transition: border-color 0.2s;
}

.role-card:hover {
  border-color: var(--border-hover);
}

.role-card--default {
  border-style: dashed;
}

.role-card-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}

.role-card-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.role-card-info {
  flex: 1;
  min-width: 0;
}

.role-card-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}

.role-card-id {
  font-size: 12px;
  color: var(--text-muted);
}

.role-card-stats {
  display: flex;
  gap: 24px;
  margin-bottom: 12px;
}

.stat-item {
  display: flex;
  flex-direction: column;
}

.stat-value {
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
}

.stat-label {
  font-size: 12px;
  color: var(--text-muted);
}

.role-card-desc {
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 12px;
  line-height: 1.5;
}

.role-card-perms {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.perm-tag {
  font-size: 11px;
  font-family: monospace;
}

/* 数据表格 */
.data-table-wrapper {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

/* 来源标签 */
.source-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}

.source-manual {
  background: rgba(59, 130, 246, 0.1);
  color: #3b82f6;
}

.source-auto {
  background: rgba(107, 114, 128, 0.1);
  color: #6b7280;
}

.source-tag {
  background: rgba(16, 185, 129, 0.1);
  color: #10b981;
}

.source-ehr {
  background: rgba(139, 92, 246, 0.1);
  color: #8b5cf6;
}

.text-muted {
  color: var(--text-muted);
  font-size: 12px;
}

/* 撤销确认 */
.revoke-info p {
  margin: 0 0 12px;
  font-size: 14px;
  color: var(--text-primary);
}

.revoke-detail {
  background: var(--bg-tertiary);
  border-radius: 8px;
  padding: 12px 16px;
  font-size: 13px;
  line-height: 1.8;
  color: var(--text-secondary);
}

.revoke-detail strong {
  color: var(--text-primary);
}

/* 表单提示 */
.form-hint {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 4px;
  line-height: 1.4;
}
</style>
