import type {
  RbacRole, RbacUserView, RbacCatalog, PageDef, OpDef, WidgetDef,
  SaveRolePayload, CreateUserPayload, UpdateUserPayload
} from '@/types/rbac'

/**
 * 前端 mock 模式（VITE_USE_MOCK=true）下的 RBAC 数据与 CRUD，内存 + localStorage 持久化。
 * 与后端 MiGu.Server/Auth/PageCatalog.cs、RbacController KnownOps/Widgets 保持对齐，
 * 让无后端时也能完整调试「权限与角色」管理页与按页面权限的菜单/路由控制。
 */

const PAGES: PageDef[] = [
  { key: 'admin-dashboard', label: '总览', group: '概览', scope: 'Platform' },
  { key: 'admin-map-monitor', label: '地图监控', group: '概览', scope: 'Platform' },
  { key: 'admin-playback', label: '调度回放', group: '概览', scope: 'Platform' },
  { key: 'admin-map-editor', label: '地图编辑', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-project-properties', label: '项目属性', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-tracks', label: '场景管理', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-cars', label: '车辆管理', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-processes', label: '进程管理', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-scripts', label: '脚本管理', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-missions', label: '任务编排', group: '设计与编排', scope: 'Platform' },
  { key: 'admin-config-system', label: '系统级配置', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-integrations', label: '外部系统对接', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-routing', label: '路径规划', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-vehicle', label: '车辆维护', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-charge', label: '充电策略', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-task', label: '任务分配', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-traffic', label: '交通管制', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-auth', label: '权限与角色', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-device', label: '设备接入', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-fleet', label: '车队生命周期', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-scenario', label: '场景模板', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-location', label: '库位管理', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-ops', label: '运营维护', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-widget', label: '自定义控件', group: '平台配置中心', scope: 'Platform' },
  { key: 'admin-config-map-monitor', label: '地图监控配置', group: '平台配置中心', scope: 'Platform' },
  { key: 'monitor-dashboard', label: '运营总览', group: '运营监控', scope: 'RCSMonitor' },
  { key: 'monitor-map', label: '地图监控', group: '运营监控', scope: 'RCSMonitor' },
  { key: 'monitor-ops', label: '运维操作', group: '运营监控', scope: 'RCSMonitor' },
  { key: 'monitor-notes', label: '运营备注', group: '运营监控', scope: 'RCSMonitor' }
]

const OPS: OpDef[] = [
  { code: '*', label: '全部操作（通配）' },
  { code: 'ops.car.pause', label: '车辆 · 暂停' },
  { code: 'ops.car.resume', label: '车辆 · 恢复' },
  { code: 'ops.car.gohome', label: '车辆 · 回库' },
  { code: 'ops.car.resetSession', label: '车辆 · 重置会话' },
  { code: 'ops.car.manualCharge', label: '车辆 · 手动充电' },
  { code: 'ops.task.pause', label: '任务 · 暂停' },
  { code: 'ops.task.cancel', label: '任务 · 取消' },
  { code: 'ops.task.reassign', label: '任务 · 改派' },
  { code: 'ops.task.boostPriority', label: '任务 · 提升优先级' },
  { code: 'monitor.note.write', label: '监控 · 写运营备注' },
  { code: 'auth.manage', label: '系统 · 权限与角色管理' }
]

const WIDGETS: WidgetDef[] = [
  { id: 'MapEditor', label: '地图编辑器' },
  { id: 'CadToolbar', label: 'CAD 工具栏' },
  { id: 'CarPanel', label: '车辆面板' },
  { id: 'MissionEditor', label: '任务编辑器' },
  { id: 'OpsActionPanel', label: '运维操作面板' },
  { id: 'ConfigCenter', label: '配置中心' }
]

interface RbacState {
  roles: RbacRole[]
  users: Array<RbacUserView & { password?: string }>
}

const STORAGE_KEY = 'simple-platform-mock-rbac'

function seed(): RbacState {
  return {
    roles: [
      {
        id: 'role-admin', name: '超级管理员', description: '拥有全部页面与操作权限的内置角色',
        scope: '*', pages: ['*'], ops: ['*'], widgetGrants: [], system: true
      },
      {
        id: 'role-ops', name: '运营人员', description: '运营监控端默认角色：可执行运维操作、查看监控',
        scope: 'RCSMonitor',
        pages: ['monitor-dashboard', 'monitor-map', 'monitor-ops', 'monitor-notes'],
        ops: [
          'ops.car.pause', 'ops.car.resume', 'ops.car.gohome', 'ops.car.resetSession',
          'ops.car.manualCharge', 'ops.task.pause', 'ops.task.cancel', 'ops.task.reassign',
          'ops.task.boostPriority', 'monitor.note.write'
        ],
        widgetGrants: [
          { widgetId: 'MapEditor', visibility: 'readonly' },
          { widgetId: 'CadToolbar', visibility: 'hidden' },
          { widgetId: 'CarPanel', visibility: 'readonly' },
          { widgetId: 'MissionEditor', visibility: 'readonly' },
          { widgetId: 'OpsActionPanel', visibility: 'interactive' },
          { widgetId: 'ConfigCenter', visibility: 'hidden' }
        ],
        system: true
      }
    ],
    users: [
      { id: 'u-admin', username: 'admin', displayName: '系统管理员', enabled: true, roleIds: ['role-admin'], scopes: [] },
      { id: 'u-ops', username: 'ops', displayName: '运营人员', enabled: true, roleIds: ['role-ops'], scopes: [] }
    ]
  }
}

function load(): RbacState {
  try {
    const raw = localStorage.getItem(STORAGE_KEY)
    if (raw) return JSON.parse(raw) as RbacState
  } catch { /* ignore */ }
  const s = seed()
  persist(s)
  return s
}

let state: RbacState = load()

function persist(s: RbacState = state) {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(s)) } catch { /* ignore */ }
}

function scopesOf(roleIds: string[]): string[] {
  const set = new Set<string>()
  for (const id of roleIds) {
    const r = state.roles.find((x) => x.id === id)
    if (!r) continue
    if (r.scope === '*') { set.add('Platform'); set.add('RCSMonitor') }
    else set.add(r.scope)
  }
  return [...set]
}

function toView(u: RbacUserView & { password?: string }): RbacUserView {
  return { id: u.id, username: u.username, displayName: u.displayName, enabled: u.enabled, roleIds: [...u.roleIds], scopes: scopesOf(u.roleIds) }
}

function newId() { return Math.random().toString(36).slice(2, 10) }
function delay(ms: number) { return new Promise((r) => setTimeout(r, ms)) }
function sanitizePages(pages: string[]): string[] {
  if (pages.includes('*')) return ['*']
  const valid = new Set(PAGES.map((p) => p.key))
  return [...new Set(pages.filter((p) => valid.has(p)))]
}

export function mockRbacCatalog(): RbacCatalog {
  return {
    pages: PAGES,
    ops: OPS,
    widgets: WIDGETS,
    scopes: [
      { value: 'Platform', label: '管理端 (Platform)' },
      { value: 'RCSMonitor', label: '运营端 (RCSMonitor)' },
      { value: '*', label: '通用 (全部域)' }
    ]
  }
}

export async function mockRbacRoles(): Promise<RbacRole[]> {
  await delay(60)
  return state.roles.map((r) => ({ ...r, pages: [...r.pages], ops: [...r.ops], widgetGrants: [...r.widgetGrants] }))
}

export async function mockRbacSaveRole(payload: SaveRolePayload): Promise<RbacRole> {
  await delay(80)
  if (!payload.name?.trim()) throw new Error('角色名称不能为空')
  const role: RbacRole = {
    id: payload.id ?? `role-${newId()}`,
    name: payload.name.trim(),
    description: payload.description?.trim() ?? '',
    scope: payload.scope,
    pages: sanitizePages(payload.pages ?? []),
    ops: [...new Set(payload.ops ?? [])],
    widgetGrants: payload.widgetGrants ?? [],
    system: false
  }
  const idx = payload.id ? state.roles.findIndex((r) => r.id === payload.id) : -1
  if (idx >= 0) { role.system = state.roles[idx].system; state.roles[idx] = role } else state.roles.push(role)
  persist()
  return role
}

export async function mockRbacDeleteRole(id: string): Promise<void> {
  await delay(60)
  const role = state.roles.find((r) => r.id === id)
  if (!role) throw new Error('角色不存在')
  if (role.system) throw new Error('内置系统角色不可删除')
  const inUse = state.users.filter((u) => u.roleIds.includes(id)).map((u) => u.username)
  if (inUse.length) throw new Error(`角色仍被 ${inUse.length} 个用户使用（${inUse.slice(0, 5).join(', ')}），请先解除关联`)
  state.roles = state.roles.filter((r) => r.id !== id)
  persist()
}

export async function mockRbacUsers(): Promise<RbacUserView[]> {
  await delay(60)
  return state.users.map(toView)
}

export async function mockRbacCreateUser(payload: CreateUserPayload): Promise<RbacUserView> {
  await delay(80)
  if (!payload.username?.trim()) throw new Error('用户名不能为空')
  if (!payload.password) throw new Error('初始密码不能为空')
  if (state.users.some((u) => u.username.toLowerCase() === payload.username.trim().toLowerCase()))
    throw new Error(`用户名 ${payload.username} 已存在`)
  const valid = new Set(state.roles.map((r) => r.id))
  const u = {
    id: `u-${newId()}`,
    username: payload.username.trim(),
    displayName: payload.displayName?.trim() || payload.username.trim(),
    enabled: payload.enabled,
    roleIds: [...new Set((payload.roleIds ?? []).filter((r) => valid.has(r)))],
    scopes: [] as string[],
    password: payload.password
  }
  state.users.push(u)
  persist()
  return toView(u)
}

export async function mockRbacUpdateUser(id: string, payload: UpdateUserPayload): Promise<RbacUserView> {
  await delay(80)
  const u = state.users.find((x) => x.id === id)
  if (!u) throw new Error('用户不存在')
  if (payload.displayName !== undefined) u.displayName = payload.displayName.trim()
  if (payload.roleIds !== undefined) {
    const valid = new Set(state.roles.map((r) => r.id))
    u.roleIds = [...new Set(payload.roleIds.filter((r) => valid.has(r)))]
  }
  if (payload.enabled !== undefined) u.enabled = payload.enabled
  persist()
  return toView(u)
}

export async function mockRbacSetPassword(id: string, password: string): Promise<void> {
  await delay(60)
  const u = state.users.find((x) => x.id === id)
  if (!u) throw new Error('用户不存在')
  if (!password) throw new Error('密码不能为空')
  u.password = password
  persist()
}

export async function mockRbacDeleteUser(id: string): Promise<void> {
  await delay(60)
  if (!state.users.some((u) => u.id === id)) throw new Error('用户不存在')
  state.users = state.users.filter((u) => u.id !== id)
  persist()
}

/** 供 mockLogin 计算 allowedPages：按 username + scope 取角色 pages 并集；未知用户给该 scope 全部页面。 */
export function mockComputeAllowedPages(username: string, scope: 'Platform' | 'RCSMonitor'): string[] {
  const scopeKeys = PAGES.filter((p) => p.scope === scope).map((p) => p.key)
  const u = state.users.find((x) => x.username.toLowerCase() === username.toLowerCase())
  if (!u) return scopeKeys
  const roles = state.roles.filter((r) => u.roleIds.includes(r.id) && (r.scope === '*' || r.scope === scope))
  const set = new Set<string>()
  for (const r of roles) {
    if (r.pages.includes('*')) scopeKeys.forEach((k) => set.add(k))
    else r.pages.filter((p) => scopeKeys.includes(p)).forEach((k) => set.add(k))
  }
  return [...set]
}
