import { query, withTransaction } from '../../db/client.js'
import { createHttpError } from '../../utils/http.js'

export const ADMIN_PERMISSION_KEYS = [
  'finance.view',
  'finance.review',
  'finance.config',
  'finance.export',
  'worker_order.view',
  'worker_order.edit',
  'worker_order.configure_share',
  'worker_order.assign',
  'worker_order.return_to_hall',
  'worker_order.cancel',
  'worker_order.cancel_share',
  'worker_order.delete',
  'worker_order.publish',
  'worker_order.accept',
  'worker_order.reopen',
  'worker_order.update_material',
  'worker_order.manage_problem',
  'worker_order.deduct_deposit',
  'worker_cancel_request.review',
] as const

export type AdminPermissionKey = (typeof ADMIN_PERMISSION_KEYS)[number]

type PermissionRow = {
  permission_key: string
  permission_name: string
  permission_group: string
  description: string
}

export async function listAdminPermissionKeysForRole(role: string): Promise<string[]> {
  const result = await query<{ permission_key: string }>(
    `
      SELECT arp.permission_key
      FROM admin_role_permissions arp
      WHERE arp.role_key = $1
      ORDER BY arp.permission_key
    `,
    [
      String(role || '')
        .trim()
        .toLowerCase(),
    ],
  )
  return result.rows.map((row) => String(row.permission_key || '').trim()).filter(Boolean)
}

export async function listAdminRolesWithPermissions() {
  const result = await query<
    PermissionRow & { role_key: string; role_name: string; role_description: string }
  >(
    `
      SELECT
        ar.role_key,
        ar.role_name,
        ar.description AS role_description,
        ap.permission_key,
        ap.permission_name,
        ap.permission_group,
        ap.description
      FROM admin_roles ar
      CROSS JOIN admin_permissions ap
      ORDER BY ar.role_key, ap.permission_group, ap.permission_key
    `,
  )

  const roleMap = new Map<
    string,
    {
      roleKey: string
      roleName: string
      description: string
      permissions: Array<{
        permissionKey: string
        permissionName: string
        permissionGroup: string
        description: string
        enabled: boolean
      }>
    }
  >()

  const enabled = await query<{ role_key: string; permission_key: string }>(
    'SELECT role_key, permission_key FROM admin_role_permissions',
  )
  const enabledSet = new Set(enabled.rows.map((row) => `${row.role_key}:${row.permission_key}`))

  for (const row of result.rows) {
    let role = roleMap.get(row.role_key)
    if (!role) {
      role = {
        roleKey: row.role_key,
        roleName: row.role_name,
        description: row.role_description,
        permissions: [],
      }
      roleMap.set(row.role_key, role)
    }
    role.permissions.push({
      permissionKey: row.permission_key,
      permissionName: row.permission_name,
      permissionGroup: row.permission_group,
      description: row.description,
      enabled: enabledSet.has(`${row.role_key}:${row.permission_key}`),
    })
  }

  return { roles: Array.from(roleMap.values()) }
}

export async function updateAdminRolePermissions(roleKey: unknown, permissionKeys: unknown) {
  const normalizedRole = String(roleKey || '')
    .trim()
    .toLowerCase()
  if (!['admin', 'operator', 'support', 'finance'].includes(normalizedRole)) {
    throw createHttpError('角色不存在或不可修改', {
      statusCode: 400,
      errorCode: 'admin_role_invalid',
    })
  }

  if (!Array.isArray(permissionKeys)) {
    throw createHttpError('权限列表格式无效', {
      statusCode: 400,
      errorCode: 'admin_permissions_invalid',
    })
  }

  const requested = Array.from(
    new Set(
      permissionKeys
        .map((item) => String(item || '').trim())
        .filter((item): item is AdminPermissionKey =>
          (ADMIN_PERMISSION_KEYS as readonly string[]).includes(item),
        ),
    ),
  )

  if (normalizedRole === 'admin' && requested.length !== ADMIN_PERMISSION_KEYS.length) {
    throw createHttpError('管理员角色必须保留全部权限', {
      statusCode: 409,
      errorCode: 'admin_role_full_permissions_required',
    })
  }

  await withTransaction(async (client) => {
    await client.query('DELETE FROM admin_role_permissions WHERE role_key = $1', [normalizedRole])
    if (requested.length > 0) {
      await client.query(
        `
          INSERT INTO admin_role_permissions (role_key, permission_key)
          SELECT $1, permission_key
          FROM admin_permissions
          WHERE permission_key = ANY($2::text[])
          ON CONFLICT DO NOTHING
        `,
        [normalizedRole, requested],
      )
    }
  })

  return (await listAdminRolesWithPermissions()).roles.find(
    (role) => role.roleKey === normalizedRole,
  )
}
