import type { CartItem, CartItemType, DeliveryTask, OrderRecord } from '@/components/providers/AppProvider'
import type { Expert } from '@/types'

function normalizeApiBase(value?: string) {
  const fallback = process.env.NODE_ENV === 'production' ? '/api' : 'http://localhost:4000/api'
  const base = (value || fallback).replace(/\/+$/, '')
  return /\/api$/i.test(base) ? base : `${base}/api`
}

export const apiBase = normalizeApiBase(process.env.NEXT_PUBLIC_API_BASE_URL)
const isProduction = process.env.NODE_ENV === 'production'
const localDevAdminToken = ['dev', 'admin', 'token'].join('-')
export const adminToken = process.env.NEXT_PUBLIC_ADMIN_TOKEN || (isProduction ? '' : localDevAdminToken)
const staffTokenKey = 'dlbdi:staffToken'
const apiOrigin = apiBase.replace(/\/api\/?$/, '')
export const usesLocalApi = /^https?:\/\/(localhost|127\.0\.0\.1)(?::\d+)?\/api$/i.test(apiBase)
export const defaultPaymentChannel = usesLocalApi ? 'dev' : 'wechat_native'

export interface BackendInvoiceRequest {
  requested: true
  title: string
  taxNumber?: string
  email: string
  remark?: string
}

export function assetUrl(value?: string | null) {
  if (!value) return ''
  if (/^(https?:|data:|blob:)/.test(value)) return value
  if (value.startsWith('/')) return `${apiOrigin}${value}`
  return value
}

export interface BackendUser {
  id: string
  displayName: string
  phone: string
  passportNo: string
  wechatId?: string
  contactPhone?: string
  email: string
  organization: string
  title?: string
  city?: string
  address?: string
  industry?: string
  invoiceTitle?: string
  taxNumber?: string
  invoiceEmail?: string
  membershipLevel: 'registered' | 'junior' | 'senior'
  onboardingCompleted: boolean
  status?: 'active' | 'disabled'
  expertApplicationStatus?: string
  expertProfileStatus?: string
  lastLoginAt?: string | null
  createdAt: string
  updatedAt?: string
}

export interface BackendAdminUser extends BackendUser {
  orderCount?: number
  taskCount?: number
  consultingCount?: number
  dataServiceCount?: number
  courseRegistrationCount?: number
  eventRegistrationCount?: number
  expertBookingCount?: number
  expertApplicationStatus?: string
  expertProfileStatus?: string
}

export interface BackendAdminUserDetail {
  user: BackendAdminUser
  orders: BackendOrder[]
  tasks: BackendTask[]
  consultingRequests: BackendConsultingRequest[]
  dataServiceRequests: BackendDataServiceRequest[]
  courseRegistrations: BackendCourseRegistration[]
  eventRegistrations: BackendEventRegistration[]
  expertApplication: BackendExpertApplication | null
  expertProfile: BackendExpert | null
  expertBookings: BackendExpertBooking[]
  expertWithdrawals: BackendExpertWithdrawal[]
  settlements: BackendSettlement[]
}

export interface BackendPassportVerification {
  passportNo: string
  displayName: string
  phoneTail: string
  organization: string
  membershipLevel: BackendUser['membershipLevel']
  membershipStatus?: BackendAccountMembership['status']
  membershipExpiresAt?: string | null
  membershipDaysLeft?: number | null
  membershipSubscriptionId?: string | null
  status: 'active' | 'disabled'
  expertStatus: string
  verifiedAt: string
  createdAt: string
  updatedAt: string
}

export interface BackendProduct {
  id: string
  slug: string
  type: CartItemType
  title: string
  summary: string
  priceAmount: number
  purchaseFlow: string
  fulfillmentFlow: string
  status: 'draft' | 'published' | 'offline'
}

export interface BackendDataProduct extends BackendProduct {
  productId: string
  productStatus?: 'draft' | 'published' | 'offline'
  category: '研究报告' | '表格数据' | '政策数据库' | '资料包'
  fileFormat: 'PDF' | 'Excel' | 'CSV' | 'ZIP'
  coverUrl: string
  fileUrl: string
  fileName: string
  fileSize: number
  tags?: string[]
  caseGoal?: string
  requestOutline?: string
  deliveryOutline?: string
  serviceNote?: string
  featuredPosition: number | null
  sortOrder: number
}

export interface BackendDataServiceCase extends BackendDataProduct {
  serviceType?: string
  industryTags?: string[]
  solutionOutline?: string
  previewFileId?: string
  ctaLabel?: string
}

export interface BackendMembershipPlan {
  productId: string
  slug: string
  level: 'junior' | 'senior'
  name: string
  badge: string
  description: string
  ctaLabel: string
  tone: 'brand' | 'gold' | string
  monthlyPriceAmount: number
  yearlyPriceAmount: number
  recommended: boolean
  sortOrder: number
  status: string
  groups: { id: string; title: string; items: string[] }[]
}

export interface BackendMembershipCatalog {
  plans: BackendMembershipPlan[]
  compareRows: { id: string; label: string; registeredValue: string; juniorValue: string; seniorValue: string }[]
  faqs: { id: string; question: string; answer: string }[]
  benefits?: BackendMembershipBenefit[]
  planBenefits?: Record<string, BackendMembershipPlanBenefit[]>
}

export interface BackendMembershipBenefit {
  code: string
  label: string
  groupKey: string
  benefitType: string
  targetType: string
  targetRef?: string
  executionMode: 'display' | 'automatic' | 'manual_quote' | 'ledger' | 'manual_assignment' | string
  defaultValue?: Record<string, unknown>
  status: string
  sortOrder: number
  description?: string
  createdAt?: string
  updatedAt?: string
}

export interface BackendMembershipPlanBenefit {
  benefitCode: string
  enabled: boolean
  value?: Record<string, unknown>
  displayLabel: string
  sortOrder: number
  status: string
}

export interface BackendMembershipSubscription {
  id: string
  userId?: string
  userName?: string
  userPhone?: string
  passportNo?: string
  currentMembershipLevel?: BackendUser['membershipLevel']
  tier: 'junior' | 'senior'
  productId?: string
  billingCycle: 'monthly' | 'yearly' | 'manual_grant'
  status: 'active' | 'past_due' | 'expired' | 'canceled' | 'refunded'
  startsAt: string
  expiresAt: string
  daysLeft: number
  autoRenew: boolean
  sourceOrderId?: string | null
  latestRenewalOrderId?: string | null
  cancelRequestedAt?: string | null
  cancelRequestedReason?: string
  cancelledBy?: string
  creditedToSubscriptionId?: string | null
  paidAmountSnapshot?: number
  customerManager?: {
    assignmentId?: string
    staffAccountId?: string
    staffName?: string
    staffPhone?: string
    note?: string
    assignedAt?: string
  }
  messageCount?: number
  createdAt: string
  updatedAt?: string
}

export interface BackendMembershipEntitlementAccount {
  id: string
  userId: string
  userName?: string
  userPhone?: string
  passportNo?: string
  subscriptionId?: string | null
  benefitCode: string
  periodKey: string
  quotaTotal: number
  quotaUsed: number
  quotaRemaining: number
  validFrom: string
  validTo: string
  status: string
  metadata?: Record<string, unknown>
  updatedAt?: string
  ledger?: Array<{
    id: string
    action: string
    delta: number
    refType?: string
    refId?: string
    beforeValue: number
    afterValue: number
    payload?: Record<string, unknown>
    createdAt: string
  }>
}

export interface BackendMembershipServiceAssignment {
  id: string
  userId: string
  subscriptionId?: string | null
  assignmentType: string
  assignedStaffAccountId?: string | null
  assignedStaffName?: string
  assignedStaffPhone?: string
  status: string
  note?: string
  assignedAt: string
  endedAt?: string | null
}

export interface BackendMembershipContentDelivery {
  id: string
  title: string
  contentType: string
  eligibleTiers: string[]
  fileId?: string | null
  href?: string
  periodKey: string
  status: string
  publishedAt?: string | null
  createdAt: string
  updatedAt?: string
}

export interface BackendAccountMembership {
  level: BackendUser['membershipLevel']
  status: 'registered' | 'active' | 'expiring' | 'expired'
  tier: 'junior' | 'senior' | null
  subscription: BackendMembershipSubscription | null
  activeSubscriptions: BackendMembershipSubscription[]
  latestSubscription: BackendMembershipSubscription | null
  expiresAt: string | null
  daysLeft: number | null
  autoRenew: boolean
  canRenew: boolean
  canUpgrade: boolean
  benefits?: Array<BackendMembershipBenefit & { enabled?: boolean; value?: Record<string, unknown>; displayLabel?: string }>
  quotas?: BackendMembershipEntitlementAccount[]
  serviceAssignments?: BackendMembershipServiceAssignment[]
  contentDeliveries?: BackendMembershipContentDelivery[]
  generatedAt: string
}

export interface BackendNotification {
  id: string
  batchId?: string | null
  userId?: string
  userName?: string
  userPhone?: string
  passportNo?: string
  scene: string
  channel: 'in_app' | 'sms' | 'wechat_subscribe' | 'email'
  templateKey: string
  title: string
  body: string
  actionUrl: string
  category?: string
  payload?: Record<string, unknown>
  status: 'queued' | 'sent' | 'failed' | 'skipped' | string
  priority?: 'low' | 'normal' | 'high' | 'urgent' | string
  scheduledAt: string
  sentAt: string | null
  readAt: string | null
  failedReason?: string
  createdAt: string
  updatedAt?: string
}

export interface BackendNotificationListResponse {
  items: BackendNotification[]
  page: number
  pageSize: number
  total: number
  unreadCount?: number
}

export interface BackendNotificationPreferences {
  userId: string
  inAppEnabled: boolean
  smsEnabled: boolean
  wechatSubscribeEnabled: boolean
  emailEnabled: boolean
  quietHoursStart: string
  quietHoursEnd: string
  updatedAt?: string
}

export interface BackendNotificationTemplate {
  templateKey: string
  scene: string
  category: string
  titleTemplate: string
  bodyTemplate: string
  actionUrlTemplate: string
  defaultChannels: Array<'in_app' | 'sms' | 'wechat_subscribe' | 'email' | string>
  priority: 'low' | 'normal' | 'high' | 'urgent' | string
  variablesSchema?: Record<string, unknown>
  status: 'active' | 'disabled' | string
  sortOrder: number
  createdAt: string
  updatedAt?: string
}

export type BackendNotificationTargetType =
  | 'all'
  | 'user_ids'
  | 'membership_level'
  | 'order_status'
  | 'service_status'
  | 'course_registrations'
  | 'event_registrations'
  | 'experts'

export interface BackendNotificationBatch {
  id: string
  batchNo: string
  title: string
  body: string
  actionUrl: string
  targetType: BackendNotificationTargetType
  targetFilters: Record<string, unknown>
  channels: Array<'in_app' | 'sms' | 'wechat_subscribe' | 'email' | string>
  priority?: 'low' | 'normal' | 'high' | 'urgent' | string
  status: 'draft' | 'scheduled' | 'sending' | 'sent' | 'failed' | 'cancelled' | string
  scheduledAt: string | null
  sentAt: string | null
  recipientCount: number
  sentCount: number
  skippedCount: number
  createdBy: string
  createdAt: string
  updatedAt?: string
  previewRecipients?: Array<{ userId: string; userName?: string; userPhone?: string; passportNo?: string; membershipLevel?: string }>
  messages?: BackendNotification[]
}

export interface BackendAgentProduct extends BackendProduct {
  coverUrl: string
  scenarioTags: string[]
  detailDescription: string
  deliveryNote: string
  registeredAccess: 'closed' | 'free' | 'paid'
  juniorAccess: 'closed' | 'free' | 'paid'
  seniorAccess: 'closed' | 'free' | 'paid'
  registeredPriceAmount: number
  juniorPriceAmount: number
  seniorPriceAmount: number
  redeemableByMember?: boolean
  recommended: boolean
  sortOrder: number
}

export interface BackendAgentCatalog {
  categories: { id: string; name: string; sortOrder: number }[]
  workflow: {
    id: string
    title: string
    scene: string
    result: string
    imageUrl?: string
    nodes: { id: string; label: string; title: string; detail: string; x: number; y: number; size: string }[]
  } | null
  items: BackendAgentProduct[]
}

export interface BackendCourseProduct extends BackendProduct {
  productId: string
  productStatus?: 'draft' | 'published' | 'offline'
  instructor: string
  courseType: 'free' | 'paid' | 'junior' | 'senior'
  memberLevelRequired: 0 | 1 | 2
  lessonCount: number
  startsAt: string | null
  location: string
  courseStatus: 'upcoming' | 'ongoing' | 'completed' | 'anytime'
  direction: string
  courseFormat: string
  accessPolicy: 'free_all' | 'paid_all' | 'member_free_guest_paid' | 'members_only_free' | 'junior_paid_senior_free' | 'senior_only_free'
  registeredAccess: 'closed' | 'free' | 'paid'
  juniorAccess: 'closed' | 'free' | 'paid'
  seniorAccess: 'closed' | 'free' | 'paid'
  registeredPriceAmount: number
  juniorPriceAmount: number
  seniorPriceAmount: number
  coverUrl: string
  liveUrl: string
  replayUrl: string
  coverLabel: string
  capacity: number
  registeredCount: number
  checkedInCount?: number
  checkinRequired: boolean
  recommended: boolean
  audience: string
  outcomes: string[]
  modules: string[]
  lessonModules: {
    id: string
    title: string
    description: string
    videoUrl: string
    materialUrl: string
    durationMinutes: number
    sortOrder: number
    status: string
  }[]
  accessNote: string
  sortOrder: number
}

export interface BackendCourseCatalog {
  items: BackendCourseProduct[]
}

export interface BackendCourseRegistration {
  id: string
  registrationNo?: string
  userId: string
  userName?: string
  userPhone?: string
  userOrganization?: string
  membershipLevel?: 'registered' | 'junior' | 'senior'
  productId: string
  orderId: string
  orderNo?: string
  status: 'pending_payment' | 'registered' | 'waitlisted' | 'cancel_requested' | 'cancelled' | 'checked_in' | 'no_show' | 'refunded'
  checkinCode: string
  checkedInAt: string | null
  checkinSource?: string
  checkinNote?: string
  checkedInByStaffId?: string | null
  checkedInByStaffName?: string | null
  alreadyRegistered?: boolean
  alreadyCheckedIn?: boolean
  createdAt: string
  updatedAt: string
  course: BackendCourseProduct
}

export interface BackendEventProduct extends Omit<BackendProduct, 'status'> {
  productId: string
  productStatus?: 'draft' | 'published' | 'offline'
  status: 'draft' | 'published' | 'registration_closed' | 'offline' | 'deleted'
  eventType: 'public' | 'pro' | 'max' | 'free'
  topic: '峰会论坛' | '政策研讨' | 'AI应用' | '数据安全' | '企业参访'
  eventFormat: '线下活动' | '线上活动' | '工作坊' | '参访交流'
  coverUrl: string
  coverLabel: string
  audience: string
  highlights: string[]
  agenda: string[]
  startsAt: string | null
  endsAt: string | null
  location: string
  isOnline: boolean
  onlineUrl: string
  capacity: number
  registeredCount: number
  realRegisteredCount?: number
  checkedInCount?: number
  registrationStatus?: 'not_started' | 'open' | 'closed' | 'full' | 'finished'
  registrationStats?: {
    total: number
    paid: number
    waitlisted: number
    checkedIn: number
    cancelled: number
  }
  formSchema?: {
    key: string
    label: string
    type: 'text' | 'select' | 'textarea' | 'checkbox'
    required: boolean
    options?: string[]
  }[]
  initialRegisteredCount: number
  registeredAccess: 'closed' | 'free' | 'paid'
  juniorAccess: 'closed' | 'free' | 'paid'
  seniorAccess: 'closed' | 'free' | 'paid'
  registeredPriceAmount: number
  juniorPriceAmount: number
  seniorPriceAmount: number
  memberLevelRequired: 0 | 1 | 2
  recommended: boolean
  sortOrder: number
}

export interface BackendEventCatalog {
  items: BackendEventProduct[]
}

export interface BackendEventRegistration {
  id: string
  registrationNo?: string
  userId: string
  userName?: string
  userPhone?: string
  userOrganization?: string
  membershipLevel?: 'registered' | 'junior' | 'senior'
  productId: string
  orderId: string
  orderNo?: string
  status: 'pending_payment' | 'registered' | 'waitlisted' | 'cancel_requested' | 'cancelled' | 'checked_in' | 'no_show' | 'refunded'
  checkinCode: string
  checkedInAt: string | null
  checkinSource?: string
  checkinNote?: string
  checkedInByStaffId?: string | null
  checkedInByStaffName?: string | null
  alreadyRegistered?: boolean
  alreadyCheckedIn?: boolean
  createdAt: string
  updatedAt: string
  event: BackendEventProduct
}

export type BackendCheckinProject = (BackendEventProduct | BackendCourseProduct) & {
  kind: 'event' | 'course'
  productId: string
  pendingCount?: number
}

export type BackendCheckinRegistration = (BackendEventRegistration | BackendCourseRegistration) & {
  kind: 'event' | 'course'
  productKind?: 'event' | 'course'
}

export interface BackendCheckinRegistrationList {
  items: BackendCheckinRegistration[]
  summary: {
    total: number
    registered: number
    checkedIn: number
    pendingPayment: number
    waitlisted: number
    cancelled: number
  }
  page: number
  pageSize: number
  total: number
}

export interface BackendNewsArticle {
  id: string
  slug: string
  title: string
  categoryCode?: string
  category: string
  summary: string
  content: string
  authorName: string
  coverUrl?: string | null
  status: 'draft' | 'published' | 'offline'
  featuredPosition: number | null
  relatedArticleIds: string[]
  publishedAt: string | null
  createdAt: string
  updatedAt: string
}

export interface BackendNewsCategory {
  code: string
  name: string
  description: string
  sortOrder: number
  status: 'active' | 'disabled'
  articleCount?: number
  createdAt?: string
  updatedAt?: string
}

export interface BackendFileRef {
  id: string
  fileName: string
  mimeType: string
  fileSize: number
  url: string
}

export interface BackendExpert {
  id: string
  userId?: string | null
  passportNo?: string
  contactPhone?: string
  slug: string
  name: string
  title: string
  organization: string
  bio: string
  specialties: string[]
  directions?: string[]
  projectExperience?: string
  representativeAchievements?: string
  homepageIntro?: string
  priceAmount: number
  shareRatio?: number
  acceptingOrders?: boolean
  availabilityStatus: Expert['availabilityStatus']
  rating: number
  consultationCount: number
  photoUrl?: string | null
  status: 'draft' | 'published' | 'offline'
  createdAt: string
  updatedAt: string
  user?: BackendUser | null
  bookingCount?: number
  completedBookingCount?: number
}

export interface BackendExpertDirection {
  id: string
  groupName: string
  directionType?: string
  name: string
  description?: string
  sortOrder: number
  status: 'active' | 'disabled'
  createdAt?: string
  updatedAt?: string
}

export interface BackendExpertApplication {
  id: string
  applicationNo?: string
  userId: string
  passportNo: string
  name: string
  contactPhone: string
  organization: string
  title: string
  directions: string[]
  photoFileId?: string | null
  photoUrl: string
  projectExperience: string
  representativeAchievements: string
  homepageIntro: string
  attachmentFileIds: string[]
  attachments?: { id: string; fileName: string; mimeType: string; fileSize: number; url: string }[]
  status: 'pending' | 'approved' | 'rejected' | 'withdrawn'
  rejectReason: string
  reviewPriceAmount: number
  reviewShareRatio: number
  reviewPublish: boolean
  expertProfileId?: string | null
  user?: BackendUser
  createdAt: string
  updatedAt: string
}

export interface BackendExpertSlot {
  id: string
  expertId: string
  startsAt: string
  endsAt: string
  status: 'open' | 'booked' | 'closed'
  note: string
  createdAt: string
  updatedAt: string
}

export interface BackendExpertBooking {
  id: string
  bookingNo: string
  expertId: string
  userId: string
  passportNo: string
  orderId?: string | null
  slotId?: string | null
  startsAt: string
  endsAt: string
  contactName: string
  contactPhone: string
  background: string
  question: string
  materialFileIds: string[]
  materialFiles?: BackendFileRef[]
  status: 'pending_payment' | 'pending_expert' | 'confirmed' | 'rejected' | 'cancelled' | 'pending_user_confirm' | 'disputed' | 'completed'
  statusReason: string
  holdExpiresAt?: string | null
  cancelledAt?: string | null
  cancelledBy?: string
  completionSubmittedAt?: string | null
  userConfirmedAt?: string | null
  disputedAt?: string | null
  disputeReason?: string
  meetingUrl: string
  meetingMethod?: string
  meetingPlatform?: string
  meetingNo?: string
  meetingPassword?: string
  meetingNote?: string
  meetingInternalNote?: string
  meetingUpdatedAt?: string | null
  pendingChange?: {
    id: string
    requesterType: 'user' | 'expert' | 'admin'
    changeType: 'reschedule' | 'cancel'
    requestedStartsAt: string
    requestedEndsAt: string
    reason: string
    status: 'requested' | 'proposed' | 'accepted' | 'rejected' | 'cancelled' | string
    userConfirmedAt?: string | null
    expertConfirmedAt?: string | null
    adminNote?: string
    createdAt: string
  } | null
  completedAt?: string | null
  expert: BackendExpert
  user: BackendUser
  createdAt: string
  updatedAt: string
}

export interface BackendExpertWithdrawal {
  id: string
  withdrawalNo?: string
  expertId: string
  userId: string
  passportNo: string
  amount: number
  payeeName: string
  bankAccount: string
  bankName: string
  status: 'pending' | 'completed' | 'rejected'
  adminNote: string
  handledBy?: string
  handledAt?: string | null
  paidAt?: string | null
  paidBank?: string
  paymentSerialNo?: string
  paymentProofFileId?: string | null
  payoutNote?: string
  items?: Array<{
    id: string
    settlementId: string
    settlementNo: string
    orderId: string
    orderNo: string
    productTitle: string
    amount: number
    settlementStatus: string
    createdAt: string
  }>
  expert: BackendExpert
  user: BackendUser
  createdAt: string
  updatedAt: string
}

export interface BackendExpertWallet {
  expertId: string
  availableAmount: number
  lockedAmount: number
  withdrawnAmount: number
  pendingSettlementAmount: number
  items: Array<{
    id: string
    settlementNo?: string
    orderId: string
    grossAmount: number
    expertShareAmount: number
    availableAmount: number
    lockedAmount: number
    withdrawnAmount: number
    status: string
    availableAt?: string | null
    createdAt: string
    updatedAt?: string
  }>
}

export interface BackendSiteAgreement {
  id: string
  title: string
  summary: string
  content: string
  status: 'draft' | 'published'
  updatedBy: string
  createdAt: string
  updatedAt: string
}

export interface BackendOrderItem {
  productId: string
  productType: CartItemType
  titleSnapshot: string
  unitPriceAmount: number
  listPriceAmount?: number
  memberPriceAmount?: number | null
  memberDiscountAmount?: number
  accessState?: 'closed' | 'free' | 'paid' | null
  pricingSource?: 'matrix' | 'expert_discount' | 'membership_plan' | 'manual_quote' | 'list_price' | string
  membershipChange?: BackendMembershipChange | null
  membershipDiscountNote?: string
  membershipLevelSnapshot?: BackendUser['membershipLevel'] | string
  quantity: number
  payableAmount: number
  billingCycle?: 'once' | 'monthly' | 'yearly' | 'manual_grant'
  fulfillmentStatus?: string
  serviceEntryType?: CartItemType | string
  serviceEntryId?: string
  serviceEntryHref?: string
  expertBookingId?: string | null
  dataServiceRequestId?: string | null
  consultingRequestId?: string | null
}

export interface BackendMembershipChange {
  type: 'activate' | 'renew' | 'upgrade'
  fromLevel: BackendUser['membershipLevel']
  toLevel: 'junior' | 'senior'
  upgradeCreditAmount: number
  creditedSubscriptionIds?: string[]
}

export interface BackendOrder {
  id: string
  orderNo: string
  settlementNo?: string
  userId: string
  userPhone?: string
  status: 'pending_payment' | 'paid' | 'completed' | 'closed'
  items: BackendOrderItem[]
  subtotalAmount: number
  memberDiscountAmount: number
  couponDiscountAmount: number
  paidAmount: number
  totalAmount: number
  currency: 'CNY'
  settlementSnapshot?: unknown
  invoiceStatus?: BackendInvoiceStatus | ''
  invoiceApplication?: BackendInvoiceApplication | null
  createdAt: string
  updatedAt: string
}

export type BackendInvoiceStatus = 'pending' | 'processing' | 'issued' | 'rejected' | 'failed'

export interface UploadedFileSummary {
  id: string
  fileName: string
  mimeType?: string | null
  fileSize?: number | null
  url?: string
  createdAt?: string | null
}

export interface BackendInvoiceApplication {
  id: string
  invoiceNo: string
  invoiceType: 'normal_e_invoice' | string
  invoiceTypeLabel?: string
  orderId: string
  orderNo: string
  settlementNo?: string | null
  userId: string
  userPhone?: string | null
  title: string
  taxNumber?: string | null
  email: string
  amount: number
  status: BackendInvoiceStatus
  provider: string
  providerInvoiceId?: string | null
  pdfFileId?: string | null
  fileName?: string | null
  fileUrl?: string | null
  failureReason?: string | null
  remark?: string | null
  adminNote?: string | null
  issuedBy?: string | null
  issuedAt?: string | null
  fileUploadedAt?: string | null
  createdAt: string
  updatedAt: string
}

export type BackendPaymentChannel = 'dev' | 'wechat_jsapi' | 'wechat_native'

export interface BackendJsapiPaymentParams {
  timeStamp: string
  nonceStr: string
  package: string
  signType: 'RSA'
  paySign: string
}

export interface BackendPaymentOrder {
  id: string
  paymentNo: string
  legacyPaymentNo?: string | null
  orderId: string
  orderNo: string
  settlementNo?: string | null
  userId: string
  userPhone?: string | null
  provider?: string
  channel: string
  amount: number
  status: 'created' | 'paying' | 'succeeded' | 'expired' | 'failed' | 'closed' | string
  prepayId?: string | null
  codeUrl?: string | null
  channelTradeNo?: string | null
  payerOpenid?: string | null
  jsapiParams?: BackendJsapiPaymentParams
  paidAt?: string | null
  closedAt?: string | null
  failureCode?: string | null
  failureMessage?: string | null
  expiresAt: string
  createdAt: string
  updatedAt: string
  order?: BackendOrder
  itemSummary?: string
}

export type BackendOperationalEventStatus = 'open' | 'acknowledged' | 'resolved' | 'ignored'
export type BackendOperationalEventSeverity = 'info' | 'warning' | 'error' | 'critical'

export interface BackendOperationalEvent {
  id: string
  severity: BackendOperationalEventSeverity
  eventType: string
  resourceType: string
  resourceId: string
  message: string
  payload?: Record<string, unknown>
  status: BackendOperationalEventStatus
  handlerNote?: string
  handledAt?: string | null
  resolvedAt?: string | null
  handlerName?: string
  linkedHref?: string
  createdAt: string
  updatedAt?: string
}

export interface BackendOperationalEventList {
  items: BackendOperationalEvent[]
  summary: {
    open: number
    acknowledged: number
    resolved: number
    critical: number
    error: number
  }
  page: number
  pageSize: number
  total: number
}

export interface BackendDashboardMetric {
  key: string
  label: string
  value: number
  valueType: 'money' | 'number' | string
  helper?: string
  href?: string
}

export interface BackendDashboardQueueItem {
  key: string
  label: string
  count: number
  tone?: 'danger' | 'warning' | 'default' | string
  href?: string
  description?: string
}

export interface BackendDashboardLine {
  key: string
  label: string
  total: number
  pending: number
  active: number
  completed: number
  risk: number
  activeType?: 'money' | string
  href?: string
}

export interface BackendDashboardListItem {
  key: string
  label: string
  title: string
  description?: string
  status?: string
  amount?: number
  href?: string
  createdAt?: string
  updatedAt?: string
}

export interface BackendAdminDashboardSummary {
  range: { key: string; label: string }
  capabilities: Record<string, boolean>
  metrics: BackendDashboardMetric[]
  workQueues: BackendDashboardQueueItem[]
  businessLines: BackendDashboardLine[]
  risks: BackendOperationalEvent[]
  recentOrders: BackendDashboardListItem[]
  fulfillmentQueue: BackendDashboardListItem[]
}

export interface BackendHealthDeep {
  status: 'ok' | 'degraded' | 'error' | string
  service: string
  mode: string
  timestamp: string
  checks: Record<string, {
    status: 'ok' | 'warning' | 'error' | string
    configured?: boolean
    enabled?: boolean
    message?: string
    code?: string
    latencyMs?: number
    [key: string]: unknown
  }>
}

export interface BackendSystemConfigCheck {
  key: string
  group: string
  label: string
  status: 'ok' | 'warning' | 'error' | string
  required: boolean
  configured: boolean
  message: string
  suggestion?: string
  details?: Record<string, unknown>
}

export interface BackendOpsJob {
  key: string
  name: string
  description: string
  permission?: string
  status?: string
  lastRunAt?: string | null
  lastResult?: Record<string, unknown> | null
  startedAt?: string
  finishedAt?: string
  result?: unknown
}

export interface BackendRevenueRow {
  id: string
  date: string
  orderNo: string
  paymentNo?: string | null
  settlementNo?: string | null
  userPhone?: string | null
  itemSummary: string
  productType: string
  paymentChannel?: string | null
  paymentStatus?: string | null
  orderStatus: string
  subtotalAmount: number
  memberDiscountAmount: number
  couponDiscountAmount: number
  totalAmount: number
  paidAmount: number
  expertShareAmount: number
  expertPlatformShareAmount: number
  platformKeepAmount: number
  createdAt: string
  updatedAt: string
  paymentCreatedAt?: string | null
  paymentUpdatedAt?: string | null
}

export interface BackendRevenueReport {
  summary: {
    dealAmount: number
    paidAmount: number
    platformIncomeAmount: number
    nonExpertIncomeAmount: number
    expertPlatformShareAmount: number
    expertPayableAmount: number
    orderCount: number
    paymentCount: number
  }
  items: BackendRevenueRow[]
}

export type BackendReconcileRow = BackendRevenueRow

export interface BackendTask {
  id: string
  taskNo?: string
  orderId: string
  orderNo?: string
  userPhone?: string
  productId: string
  productTitle?: string
  type: CartItemType
  title: string
  status: string
  priority: string
  assigneeAccountId?: string
  assigneeName?: string
  acceptedAt?: string
  progressNote?: string
  resultSummary?: string
  materialPayload?: {
    organization?: string
    contact?: string
    background?: string
    fileIds?: string[]
    files?: UploadedFileSummary[]
    [key: string]: unknown
  }
  materials?: UploadedFileSummary[]
  fileIds?: string[]
  submittedAt?: string | null
  reviewNote?: string
  deliverables?: UploadedFileSummary[]
  completedAt?: string
  createdAt: string
  updatedAt: string
}

export interface BackendCoupon {
  id: string
  code: string
  name: string
  description?: string
  discountType: 'amount' | 'percent'
  discountValue: number
  maxDiscountAmount?: number | null
  minOrderAmount: number
  productScope?: {
    mode?: 'all' | 'include'
    productTypes?: string[]
    productIds?: string[]
    excludeProductIds?: string[]
  }
  userScope?: {
    membershipLevels?: Array<'registered' | 'junior' | 'senior'>
    passportNos?: string[]
    userIds?: string[]
    firstOrderOnly?: boolean
    newUserOnly?: boolean
  }
  usageLimits?: {
    perUser?: number
    perDay?: number
  }
  stackingPolicy?: {
    allowMemberDiscount?: boolean
  }
  budgetAmount?: number | null
  usedDiscountAmount?: number
  totalQuantity: number
  usedQuantity: number
  remainingQuantity: number
  startsAt: string
  endsAt: string | null
  status: 'active' | 'paused' | 'expired'
}

export interface BackendCouponRedemption {
  id: string
  couponId: string
  couponCode: string
  couponName: string
  userId: string
  userName?: string | null
  userPhone?: string | null
  passportNo?: string | null
  orderId: string
  orderNo: string
  discountAmount: number
  discountBaseAmount: number
  ruleSnapshot?: Record<string, unknown>
  createdAt: string
}

export interface BackendSettlement {
  id: string
  settlementNo?: string
  orderId: string
  orderNo: string
  userPhone: string
  productId: string
  productTitle: string
  expertId?: string | null
  expertName?: string
  beneficiaryUserId?: string | null
  passportNo?: string
  grossAmount: number
  expertShareAmount: number
  platformShareAmount: number
  availableAmount?: number
  lockedAmount?: number
  withdrawnAmount?: number
  availableAt?: string | null
  status: string
  createdAt: string
}

export interface BackendConsultingRequest {
  id: string
  requestNo: string
  userId: string
  status: 'pending' | 'assigned' | 'communicating' | 'planning' | 'proposal_ready' | 'pending_payment' | 'in_service' | 'completed' | 'cancelled'
  currentStep: number
  company: string
  contactName: string
  contactPhone: string
  email: string
  direction: string
  organizationType: string
  industry: string
  city: string
  projectStage: string
  urgency: string
  budgetRange: string
  expectedStart: string
  currentSituation: string
  requirement: string
  goals: string
  preferredContactTime: string
  owner: string
  assignedAccountId?: string
  assigneeName?: string
  progressNote?: string
  solutionSummary?: string
  chargeRequired?: boolean
  quotedTitle?: string
  quotedAmount?: number
  originalQuotedAmount?: number
  membershipDiscountAmount?: number
  membershipDiscountNote?: string
  membershipLevelSnapshot?: BackendUser['membershipLevel'] | string
  quotedNote?: string
  quotedAt?: string | null
  confirmedAt?: string | null
  orderId?: string | null
  paidAt?: string | null
  finalSummary?: string
  finalFileId?: string | null
  finalFileUrl?: string
  internalNote?: string
  acceptedAt?: string | null
  completedAt?: string | null
  createdAt: string
  updatedAt: string
}

export interface BackendDataServiceRequest {
  id: string
  requestNo: string
  userId: string
  userPhone?: string
  orderId?: string | null
  orderNo?: string | null
  status: 'pending_contact' | 'contacting' | 'quoted' | 'pending_payment' | 'in_service' | 'completed' | 'cancelled'
  currentStep: number
  company: string
  organizationType: string
  contactName: string
  contactPhone: string
  email: string
  city: string
  dataTopic: string
  serviceType: string
  regionScope: string
  timeRange: string
  industryScene: string
  expectedFormat: string
  dataVolume: string
  usagePurpose: string
  requirement: string
  expectedResult: string
  deadline: string
  budgetRange: string
  sensitiveData: boolean
  preferredContactTime: string
  extraNote: string
  assignedAccountId?: string | null
  assigneeName?: string | null
  contactNote: string
  progressNote: string
  quotedTitle: string
  quotedAmount: number
  originalQuotedAmount?: number
  membershipDiscountAmount?: number
  membershipDiscountNote?: string
  membershipLevelSnapshot?: BackendUser['membershipLevel'] | string
  quotedNote: string
  quotedAt?: string | null
  confirmedAt?: string | null
  solutionSummary?: string
  paidAt?: string | null
  deliverableFileId?: string | null
  deliverableFileIds?: string[]
  deliverableFileUrl: string
  deliverableFileName?: string | null
  deliverableFileSize?: number | null
  deliverableFiles?: UploadedFileSummary[]
  resultSummary: string
  internalNote?: string
  completedAt?: string | null
  createdAt: string
  updatedAt: string
}

export interface BackendDataServiceRequestList {
  items: BackendDataServiceRequest[]
  summary: {
    total: number
    pendingContact: number
    contacting: number
    quoted: number
    pendingPayment: number
    inService: number
    completed: number
    cancelled: number
  }
  page: number
  pageSize: number
  total: number
}

export interface BackendConsultingRequestList {
  items: BackendConsultingRequest[]
  summary: {
    total: number
    pending: number
    assigned: number
    communicating: number
    planning: number
    proposalReady: number
    pendingPayment: number
    inService: number
    completed: number
    cancelled: number
  }
  page: number
  pageSize: number
  total: number
}

export interface BackendSiteHomeSlide {
  id: string
  title: string
  imageUrl: string
  sortOrder: number
  status: 'published' | 'hidden'
  createdAt?: string
  updatedAt?: string
}

export interface BackendSiteHomeAsset {
  key: string
  label: string
  title: string
  description: string
  imageUrl: string
  sortOrder: number
  status: 'published' | 'hidden'
  createdAt?: string
  updatedAt?: string
}

export interface BackendSitePageBlockItem {
  id?: string
  itemKey: string
  title: string
  subtitle: string
  description: string
  imageUrl: string
  href: string
  ctaLabel: string
  status: 'published' | 'hidden'
  sortOrder: number
  metadata?: Record<string, unknown>
  createdAt?: string
  updatedAt?: string
}

export interface BackendSitePageBlock {
  id?: string
  pageKey?: string
  blockKey: string
  title: string
  subtitle: string
  body: string
  layout: string
  status: 'published' | 'hidden'
  sortOrder: number
  metadata?: Record<string, unknown>
  items: BackendSitePageBlockItem[]
  createdAt?: string
  updatedAt?: string
}

export type BackendRecommendationSourceType = 'news' | 'course' | 'event' | 'expert'
export type BackendRecommendationPlacement = 'home.news' | 'home.courses' | 'home.events' | 'home.experts' | 'news.carousel' | 'courses.carousel' | 'events.carousel'

export type BackendRecommendationSource = BackendNewsArticle | BackendCourseProduct | BackendEventProduct | BackendExpert

export interface BackendRecommendationCandidate {
  id: string
  sourceType: BackendRecommendationSourceType
  title: string
  subtitle: string
  imageUrl: string
  href: string
  status: string
  badge?: string
  startsAt?: string | null
  endsAt?: string | null
  priceAmount?: number
  source?: BackendRecommendationSource | null
}

export interface BackendRecommendationSlot {
  id?: string | null
  placementKey: BackendRecommendationPlacement
  slotKey: string
  sourceType: BackendRecommendationSourceType
  sourceId: string
  status: 'active' | 'hidden'
  sortOrder: number
  titleOverride: string
  subtitleOverride: string
  imageUrlOverride: string
  ctaLabelOverride: string
  hrefOverride: string
  metadata?: Record<string, unknown>
  title?: string
  subtitle?: string
  imageUrl?: string
  href?: string
  ctaLabel?: string
  badge?: string
  startsAt?: string | null
  endsAt?: string | null
  priceAmount?: number
  source?: BackendRecommendationSource | null
  warnings?: string[]
  createdAt?: string | null
  updatedAt?: string | null
}

export interface BackendRecommendationResponse {
  placements: Partial<Record<BackendRecommendationPlacement, BackendRecommendationSlot[]>>
  items: BackendRecommendationSlot[]
}

export interface BackendSiteHome {
  slides: BackendSiteHomeSlide[]
  loginSlides: BackendSiteHomeSlide[]
  assets: BackendSiteHomeAsset[]
  featuredExperts: BackendExpert[]
  blocks: BackendSitePageBlock[]
  recommendations?: {
    news: BackendRecommendationSlot[]
    courses: BackendRecommendationSlot[]
    events: BackendRecommendationSlot[]
    experts: BackendRecommendationSlot[]
  }
}

export interface BackendDataServicePage {
  blocks: BackendSitePageBlock[]
  assets: BackendSiteHomeAsset[]
}

export interface BackendSiteAboutContent {
  heroTitle: string
  heroDescription: string
  heroExplanation: string
  heroCoverUrl: string
  workTitle: string
  workDescription: string
  workImageUrl: string
  serviceTitle: string
  serviceDescription: string
  contactAddress: string
  contactPhone: string
  contactEmail: string
  contactHours: string
  updatedAt?: string
}

export interface BackendSiteAboutItem {
  id: string
  section: string
  title: string
  description: string
  imageUrl: string
  sortOrder: number
  status: 'published' | 'hidden'
  role?: string
  metadata?: Record<string, unknown>
  createdAt?: string
  updatedAt?: string
}

export interface BackendSiteAbout {
  content: BackendSiteAboutContent
  workSteps: BackendSiteAboutItem[]
  serviceObjects: BackendSiteAboutItem[]
  representativeWork: BackendSiteAboutItem[]
  cooperationModes: BackendSiteAboutItem[]
  honors: BackendSiteAboutItem[]
  partners: BackendSiteAboutItem[]
  team: BackendSiteAboutItem[]
}

export interface BackendSiteConsultingContent {
  heroTitle: string
  heroDescription: string
  heroExplanation: string
  heroImageUrl: string
  directionTitle: string
  directionDescription: string
  casesTitle: string
  casesDescription: string
  stepsTitle: string
  stepsDescription: string
  updatedAt?: string
}

export interface BackendSiteConsultingDirection {
  id: string
  slug: string
  title: string
  summary: string
  description: string
  note: string
  imageUrl: string
  scenarios: string[]
  ownerDepartment?: string
  ownerOrgUnitId?: string | null
  defaultAssigneeId?: string | null
  sortOrder: number
  status: 'published' | 'hidden'
  createdAt?: string
  updatedAt?: string
}

export interface BackendSiteConsultingCase {
  id: string
  type: string
  title: string
  summary: string
  imageUrl: string
  sortOrder: number
  status: 'published' | 'hidden'
  createdAt?: string
  updatedAt?: string
}

export interface BackendSiteConsultingStep {
  id: string
  title: string
  description: string
  sortOrder: number
  status: 'published' | 'hidden'
  createdAt?: string
  updatedAt?: string
}

export interface BackendConsultingOption {
  id?: string
  setCode?: string
  code: string
  label: string
  description: string
  sortOrder: number
  status: 'active' | 'disabled'
  metadata?: Record<string, unknown>
  createdAt?: string
  updatedAt?: string
}

export interface BackendConsultingOptionSet {
  code: string
  name: string
  description: string
  sortOrder: number
  status: 'active' | 'disabled'
  options: BackendConsultingOption[]
  createdAt?: string
  updatedAt?: string
}

export interface BackendSiteConsulting {
  content: BackendSiteConsultingContent
  directions: BackendSiteConsultingDirection[]
  cases: BackendSiteConsultingCase[]
  steps: BackendSiteConsultingStep[]
  optionSets: BackendConsultingOptionSet[]
}

export interface BackendCooperationRequest {
  id: string
  requestNo: string
  userId: string
  name: string
  phone: string
  organization: string
  demand: string
  status: 'pending' | 'completed'
  assignedAccountId?: string | null
  processNote?: string
  convertedType?: string
  convertedRefId?: string | null
  convertedAt?: string | null
  completedAt: string | null
  createdAt: string
  updatedAt: string
  user?: BackendUser
}

export interface BackendBusinessSearchResult {
  type: string
  number: string
  label: string
  title: string
  description: string
  status: string
  href: string
}

export interface BackendCheckoutPreview {
  items: BackendOrderItem[]
  subtotalAmount: number
  memberDiscountAmount: number
  couponDiscountAmount: number
  paidAmount: number
  totalAmount: number
  currency: 'CNY'
  membership?: BackendAccountMembership
  pricingBreakdown?: Array<{ code: string; label: string; amount: number; source: string }>
  membershipChange?: BackendMembershipChange | null
  couponPreview?: {
    id: string
    code: string
    name: string
    discountType: 'amount' | 'percent'
    discountValue: number
    maxDiscountAmount?: number | null
    minOrderAmount?: number
    eligibleSubtotal?: number
    discountBaseAmount?: number
    discountAmount: number
    remainingQuantity: number
    budgetAmount?: number | null
    usedDiscountAmount?: number
    productScope?: BackendCoupon['productScope']
    userScope?: BackendCoupon['userScope']
    usageLimits?: BackendCoupon['usageLimits']
    stackingPolicy?: BackendCoupon['stackingPolicy']
    eligibleItems?: Array<{ productId: string; productType: string; titleSnapshot: string; amount: number }>
    endsAt: string | null
  } | null
}

export interface StaffAccount {
  id: string
  email: string
  phone: string
  displayName: string
  role: string
  roleName?: string
  status: string
  positionTitle?: string
  orgUnitId?: string | null
  positionId?: string | null
  remark?: string
  defaultEntry?: string
  permissions: string[]
  lastLoginAt?: string | null
  createdAt?: string
  updatedAt?: string
}

export interface BackendStaffAccount extends StaffAccount {
  taskCount?: number
  consultingCount?: number
  dataServiceCount?: number
  checkinCount?: number
}

export interface BackendStaffRole {
  code: string
  name: string
  description: string
  defaultEntry: string
  status: 'active' | 'disabled' | string
  permissions: string[]
  roleFamily?: string
  roleLevel?: number
  sortOrder?: number
  isSystem?: boolean
  staffCount?: number
  activeStaffCount?: number
  createdAt?: string | null
  updatedAt?: string | null
}

export interface BackendPermissionItem {
  code: string
  label: string
  group: string
  domain?: string
  module?: string
  action?: 'read' | 'write' | 'update' | 'export' | 'admin' | string
  level?: number
  sortOrder?: number
  description: string
}

export interface BackendOrgUnit {
  id: string
  parentId?: string | null
  code: string
  name: string
  unitType: string
  path: string
  depth: number
  sortOrder: number
  status: 'active' | 'disabled' | string
  managerAccountId?: string | null
  description: string
  permissions: string[]
  staffCount: number
  createdAt?: string
  updatedAt?: string
}

export interface BackendStaffPosition {
  id: string
  orgUnitId: string
  parentPositionId?: string | null
  code: string
  name: string
  roleCode: string
  roleName?: string
  positionLevel: number
  sortOrder: number
  status: 'active' | 'disabled' | string
  description: string
  permissions: string[]
  staffCount: number
  createdAt?: string
  updatedAt?: string
}

export interface BackendStaffAssignment {
  id: string
  accountId: string
  accountName: string
  accountPhone?: string
  orgUnitId: string
  orgUnitName?: string
  positionId?: string | null
  positionName?: string | null
  roleCode: string
  roleName?: string
  isPrimary: boolean
  status: 'active' | 'disabled' | string
  createdAt?: string
  updatedAt?: string
}

export interface BackendOrgTree {
  units: BackendOrgUnit[]
  positions: BackendStaffPosition[]
  assignments: BackendStaffAssignment[]
}

export interface BackendStaffAuditLog {
  id: string
  source?: 'staff' | 'admin' | string
  actorAccountId?: string | null
  actorEmail: string
  actorName?: string
  action: string
  targetType: string
  targetId: string
  summary: string
  metadata?: Record<string, unknown>
  createdAt: string
}

export interface BackendStaffEffectivePermissions {
  accountId: string
  roleCode: string
  orgUnitId?: string | null
  positionId?: string | null
  rolePermissions: string[]
  orgPermissions: string[]
  positionPermissions: string[]
  directPermissions: string[]
  effectivePermissions: string[]
}

export interface BackendAdminPassportVerification {
  userId: string
  passportNo: string
  displayName?: string
  phoneTail?: string
  organization?: string
  membershipLevel: string
  membershipStatus?: string
  membershipExpiresAt?: string | null
  membershipDaysLeft?: number | null
  membershipSubscriptionId?: string | null
  status: string
  expertStatus?: string
  verifiedAt: string
  createdAt?: string
  updatedAt?: string
  summary?: {
    orderCount?: number
    courseRegistrationCount?: number
    eventRegistrationCount?: number
    consultingRequestCount?: number
    dataServiceRequestCount?: number
    expertBookingCount?: number
  }
}

async function request<T>(path: string, options: RequestInit = {}) {
  const isFormData = typeof FormData !== 'undefined' && options.body instanceof FormData
  const response = await fetch(`${apiBase}${path}`, {
    ...options,
    headers: {
      ...(isFormData ? {} : { 'content-type': 'application/json' }),
      ...(options.headers || {}),
    },
  })
  const text = await response.text()
  const contentType = response.headers.get('content-type') || ''
  let data: unknown = null
  if (text && contentType.includes('application/json')) {
    data = JSON.parse(text)
  } else if (text) {
    data = text
  }
  if (!response.ok) {
    const message = typeof data === 'object' && data && 'message' in data
      ? String((data as { message?: unknown }).message)
      : typeof data === 'object' && data && 'error' in data
        ? String((data as { error?: unknown }).error)
        : text || `请求失败：${response.status}`
    const error = new Error(message) as Error & { status?: number; retryAfter?: number }
    error.status = response.status
    const retryAfter = typeof data === 'object' && data && 'retryAfter' in data
      ? Number((data as { retryAfter?: unknown }).retryAfter)
      : Number(response.headers.get('retry-after') || 0)
    if (Number.isFinite(retryAfter) && retryAfter > 0) error.retryAfter = retryAfter
    throw error
  }
  return data as T
}

function normalizeDataProduct<T extends Partial<BackendDataProduct>>(item: T): T {
  return {
    ...item,
    coverUrl: assetUrl(item.coverUrl),
    fileUrl: assetUrl(item.fileUrl),
  }
}

function normalizeAgentProduct<T extends Partial<BackendAgentProduct>>(item: T): T {
  return {
    ...item,
    coverUrl: assetUrl(item.coverUrl),
  }
}

function normalizeSiteHome(home: BackendSiteHome): BackendSiteHome {
  return {
    slides: (home.slides || []).map((slide) => ({ ...slide, imageUrl: assetUrl(slide.imageUrl) })),
    loginSlides: (home.loginSlides || []).map((slide) => ({ ...slide, imageUrl: assetUrl(slide.imageUrl) })),
    assets: (home.assets || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    featuredExperts: (home.featuredExperts || []).map((expert) => ({ ...expert, photoUrl: assetUrl(expert.photoUrl) })),
    blocks: (home.blocks || []).map((block) => ({
      ...block,
      items: (block.items || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    })),
    recommendations: normalizeSiteRecommendations(home),
  }
}

function normalizeSiteAbout(about: BackendSiteAbout): BackendSiteAbout {
  const normalizeItem = (item: BackendSiteAboutItem) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })
  return {
    ...about,
    content: {
      ...about.content,
      heroCoverUrl: assetUrl(about.content?.heroCoverUrl) || '',
      workImageUrl: assetUrl(about.content?.workImageUrl) || '',
    },
    workSteps: (about.workSteps || []).map(normalizeItem),
    serviceObjects: (about.serviceObjects || []).map(normalizeItem),
    representativeWork: (about.representativeWork || []).map(normalizeItem),
    cooperationModes: (about.cooperationModes || []).map(normalizeItem),
    honors: (about.honors || []).map(normalizeItem),
    partners: (about.partners || []).map(normalizeItem),
    team: (about.team || []).map(normalizeItem),
  }
}

function normalizeSiteConsulting(site: BackendSiteConsulting): BackendSiteConsulting {
  return {
    ...site,
    content: {
      ...site.content,
      heroImageUrl: assetUrl(site.content?.heroImageUrl) || '',
    },
    directions: (site.directions || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    cases: (site.cases || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    steps: site.steps || [],
    optionSets: site.optionSets || [],
  }
}

function normalizeDataServiceRequest<T extends Partial<BackendDataServiceRequest>>(item: T): T {
  return {
    ...item,
    deliverableFileUrl: assetUrl(item.deliverableFileUrl),
  }
}

function normalizeNewsArticle<T extends Partial<BackendNewsArticle>>(article: T): T {
  return {
    ...article,
    coverUrl: assetUrl(article.coverUrl),
    content: typeof article.content === 'string'
      ? article.content.replace(/src=(["'])\/api\//g, `src=$1${apiBase.replace(/\/api\/?$/, '')}/api/`)
      : article.content,
  }
}

function normalizeCourseProduct<T extends Partial<BackendCourseProduct>>(item: T): T {
  return {
    ...item,
    coverUrl: assetUrl(item.coverUrl),
    liveUrl: assetUrl(item.liveUrl),
    replayUrl: assetUrl(item.replayUrl),
    lessonModules: item.lessonModules?.map((module) => ({
      ...module,
      videoUrl: assetUrl(module.videoUrl),
      materialUrl: assetUrl(module.materialUrl),
    })),
  }
}

function normalizeEventProduct<T extends Partial<BackendEventProduct>>(item: T): T {
  return {
    ...item,
    coverUrl: assetUrl(item.coverUrl),
  }
}

function normalizeRecommendationSource(sourceType: BackendRecommendationSourceType, source?: BackendRecommendationSource | null): BackendRecommendationSource | null {
  if (!source) return null
  if (sourceType === 'news') return normalizeNewsArticle(source as BackendNewsArticle) as BackendRecommendationSource
  if (sourceType === 'course') return normalizeCourseProduct(source as BackendCourseProduct) as BackendRecommendationSource
  if (sourceType === 'event') return normalizeEventProduct(source as BackendEventProduct) as BackendRecommendationSource
  if (sourceType === 'expert') return { ...(source as BackendExpert), photoUrl: assetUrl((source as BackendExpert).photoUrl) } as BackendRecommendationSource
  return source
}

function normalizeRecommendationSlot(slot: BackendRecommendationSlot): BackendRecommendationSlot {
  return {
    ...slot,
    imageUrl: assetUrl(slot.imageUrl),
    imageUrlOverride: assetUrl(slot.imageUrlOverride),
    source: normalizeRecommendationSource(slot.sourceType, slot.source),
  }
}

function normalizeRecommendationResponse(result: BackendRecommendationResponse): BackendRecommendationResponse {
  const placements = Object.fromEntries(Object.entries(result.placements || {}).map(([key, value]) => [
    key,
    (value || []).map(normalizeRecommendationSlot),
  ])) as BackendRecommendationResponse['placements']
  return {
    placements,
    items: (result.items || []).map(normalizeRecommendationSlot),
  }
}

function normalizeSiteRecommendations(home: BackendSiteHome): BackendSiteHome['recommendations'] {
  const recommendations = home.recommendations || { news: [], courses: [], events: [], experts: [] }
  return {
    news: (recommendations.news || []).map(normalizeRecommendationSlot),
    courses: (recommendations.courses || []).map(normalizeRecommendationSlot),
    events: (recommendations.events || []).map(normalizeRecommendationSlot),
    experts: (recommendations.experts || []).map(normalizeRecommendationSlot),
  }
}

function normalizeCourseRegistration(item: BackendCourseRegistration): BackendCourseRegistration {
  return { ...item, course: normalizeCourseProduct(item.course) }
}

function normalizeEventRegistration(item: BackendEventRegistration): BackendEventRegistration {
  return { ...item, event: normalizeEventProduct(item.event) }
}

function bearer(token: string) {
  return { authorization: `Bearer ${token}` }
}

function adminHeaders() {
  const token = getStaffToken()
  if (token) return bearer(token)
  return {}
}

function adminOrDevTokenHeaders() {
  const headers = adminHeaders()
  if (Object.keys(headers).length > 0) return headers
  return adminToken ? { 'x-admin-token': adminToken } : {}
}

export function getStaffToken() {
  if (typeof window === 'undefined') return ''
  return window.localStorage.getItem(staffTokenKey) || ''
}

export function saveStaffToken(token: string) {
  if (typeof window === 'undefined') return
  window.localStorage.setItem(staffTokenKey, token)
}

export function clearStaffToken() {
  if (typeof window === 'undefined') return
  window.localStorage.removeItem(staffTokenKey)
}

export function yuan(cents: number) {
  return Math.round(cents / 100)
}

export function cents(yuanValue: number) {
  return Math.round(yuanValue * 100)
}

export function membershipLevelFromBackend(level: BackendUser['membershipLevel']) {
  if (level === 'senior') return 2
  if (level === 'junior') return 1
  return 0
}

export function backendStatusLabel(status: BackendOrder['status']) {
  if (status === 'paid' || status === 'completed') return '已支付'
  if (status === 'closed') return '已关闭'
  return '待支付'
}

export function taskStatusLabel(status: string): DeliveryTask['status'] {
  if (status === 'completed') return '已完成'
  if (status === 'in_progress') return '交付中'
  if (status === 'assigned' || status === 'pending_confirm') return '资料审核中'
  return '待提交资料'
}

export function backendProductId(item: Pick<CartItem, 'id' | 'type' | 'dataServiceRequestId' | 'consultingRequestId'>) {
  if (item.dataServiceRequestId || item.id === 'data-service-custom') return 'data-service-custom'
  if (item.consultingRequestId || item.id === 'consulting-service-custom') return 'consulting-service-custom'
  return item.id
}

function checkoutItemPayload(item: CartItem) {
  return {
    productId: backendProductId(item),
    quantity: 1,
    billingCycle: item.billingCycle,
    expertId: item.expertId,
    expertName: item.expertName,
    expertBookingId: item.expertBookingId,
    dataServiceRequestId: item.dataServiceRequestId,
    consultingRequestId: item.consultingRequestId,
  }
}

export function mapBackendOrder(order: BackendOrder): OrderRecord {
  const items = order.items.map((item) => ({
    id: item.productId,
    type: item.productType,
    title: item.titleSnapshot,
    price: yuan(item.unitPriceAmount),
    href: `/${item.productType === 'data' ? 'data' : item.productType === 'agent' ? 'agents' : item.productType === 'event' ? 'events' : item.productType === 'course' ? 'courses' : item.productType === 'expert' ? 'experts' : 'membership'}`,
    meta: `数量 ${item.quantity}`,
    serviceEntryType: item.serviceEntryType,
    serviceEntryId: item.serviceEntryId,
    serviceEntryHref: item.serviceEntryHref,
    quantity: item.quantity,
  }))
  return {
    id: order.orderNo,
    settlementNo: order.settlementNo || order.orderNo.replace(/^ORD/, 'CKO'),
    backendId: order.id,
    createdAt: order.createdAt,
    items,
    subtotal: yuan(order.subtotalAmount),
    discount: yuan(order.memberDiscountAmount + order.couponDiscountAmount),
    total: yuan(order.totalAmount),
    paymentMethod: order.totalAmount > 0 ? 'wechat' : 'offline',
    status: backendStatusLabel(order.status),
    invoiceStatus: order.invoiceStatus || undefined,
    invoiceApplication: order.invoiceApplication || null,
    note: `后端订单 ${order.id} · 结算编号 ${order.settlementNo || order.orderNo.replace(/^ORD/, 'CKO')}`,
  }
}

export function mapBackendTask(task: BackendTask): DeliveryTask {
  const status = taskStatusLabel(task.status)
  const steps = task.type === 'agent'
    ? ['提交部署资料', '需求审核', '智能体配置', '交付验收']
    : ['提交咨询背景', '专家确认', '咨询执行', '服务归档']
  const currentStep = status === '待提交资料' ? 0 : status === '资料审核中' ? 1 : status === '交付中' ? 2 : steps.length - 1
  return {
    id: task.taskNo || task.id,
    orderId: task.orderNo || task.orderId,
    productId: task.productId,
    title: task.title,
    type: task.type,
    status,
    currentStep,
    steps,
    updatedAt: task.updatedAt,
  }
}

export function mapBackendExpert(expert: BackendExpert): Expert {
  return {
    id: expert.id,
    slug: expert.slug,
    name: expert.name,
    title: expert.title,
    organization: expert.organization,
    bio: expert.homepageIntro || expert.bio,
    specialties: expert.directions?.length ? expert.directions : expert.specialties || [],
    directions: expert.directions || expert.specialties || [],
    projectExperience: expert.projectExperience,
    representativeAchievements: expert.representativeAchievements,
    homepageIntro: expert.homepageIntro,
    pricePerHour: yuan(expert.priceAmount),
    shareRatio: expert.shareRatio,
    acceptingOrders: expert.acceptingOrders,
    availabilityStatus: expert.availabilityStatus,
    rating: Number(expert.rating || 5),
    consultationCount: expert.consultationCount || 0,
    photoUrl: assetUrl(expert.photoUrl) || undefined,
  }
}

export const backend = {
  healthDeep() {
    return request<BackendHealthDeep>('/health/deep')
  },
  adminSystemHealth() {
    return request<BackendHealthDeep>('/admin/system/health', { headers: adminHeaders() })
  },
  adminSystemConfigChecks() {
    return request<{ items: BackendSystemConfigCheck[]; summary: Record<string, number>; generatedAt: string }>('/admin/system/config-checks', { headers: adminHeaders() })
  },
  adminOpsJobs() {
    return request<{ items: BackendOpsJob[] }>('/admin/system/jobs', { headers: adminHeaders() })
  },
  runAdminOpsJob(jobKey: string) {
    return request<BackendOpsJob>(`/admin/system/jobs/${encodeURIComponent(jobKey)}/run`, {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  staffPhoneLogin(phone: string, code: string) {
    return request<{ token: string; account: StaffAccount }>('/staff-auth/phone-login', {
      method: 'POST',
      body: JSON.stringify({ phone, code }),
    })
  },
  staffMe() {
    return request<StaffAccount>('/staff-auth/me', { headers: adminHeaders() })
  },
  sendPhoneCode(phone: string) {
    return request<{ phone?: string; expiresIn?: number }>('/auth/phone/send-code', {
      method: 'POST',
      body: JSON.stringify({ phone }),
    })
  },
  loginByPhone(phone: string, code: string) {
    return request<{ token: string; user: BackendUser }>('/auth/phone/login', {
      method: 'POST',
      body: JSON.stringify({ phone, code }),
    })
  },
  loginByWechat(wechatId: string, phone = '') {
    return request<{ token: string; user: BackendUser }>('/auth/wechat/login', {
      method: 'POST',
      body: JSON.stringify({ wechatId, phone }),
    })
  },
  createPcScanLogin(redirect = '/', client?: { region?: string; device?: string; browser?: string }) {
    return request<{ sessionId: string; scene: string; qrDataUrl: string; qrUrl?: string; expiresIn: number }>('/auth/pc-scan/create', {
      method: 'POST',
      body: JSON.stringify({ redirect, client }),
    })
  },
  pcScanLoginStatus(sessionId: string) {
    return request<{ sessionId: string; status: 'pending' | 'scanned' | 'need_phone' | 'need_profile' | 'confirming' | 'confirmed' | 'expired' | 'cancelled'; redirect: string; exchangeCode?: string | null; expiresAt: string }>(`/auth/pc-scan/status?${new URLSearchParams({ sessionId }).toString()}`)
  },
  exchangePcScanLogin(sessionId: string, exchangeCode: string) {
    return request<{ token: string; user: BackendUser; redirect?: string }>('/auth/pc-scan/exchange', {
      method: 'POST',
      body: JSON.stringify({ sessionId, exchangeCode }),
    })
  },
  me(token: string) {
    return request<BackendUser>('/account/me', { headers: bearer(token) })
  },
  accountMembership(token: string) {
    return request<BackendAccountMembership>('/account/membership', { headers: bearer(token) })
  },
  cancelAccountMembership(token: string, subscriptionId: string, payload: { reason?: string } = {}) {
    return request<BackendMembershipSubscription>(`/account/membership/subscriptions/${encodeURIComponent(subscriptionId)}/cancel`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountNotifications(token: string, unreadOnlyOrFilters: boolean | { unreadOnly?: boolean; readState?: string; category?: string; scene?: string; page?: number; pageSize?: number } = false) {
    const filters = typeof unreadOnlyOrFilters === 'boolean' ? { unreadOnly: unreadOnlyOrFilters } : unreadOnlyOrFilters
    const query = new URLSearchParams()
    if (filters.unreadOnly) query.set('unreadOnly', 'true')
    if (filters.readState) query.set('readState', filters.readState)
    if (filters.category) query.set('category', filters.category)
    if (filters.scene) query.set('scene', filters.scene)
    if (filters.page) query.set('page', String(filters.page))
    if (filters.pageSize) query.set('pageSize', String(filters.pageSize))
    return request<BackendNotificationListResponse>(`/account/notifications${query.toString() ? `?${query}` : ''}`, { headers: bearer(token) })
  },
  accountNotificationUnreadCount(token: string) {
    return request<{ unreadCount: number }>('/account/notifications/unread-count', { headers: bearer(token) })
  },
  markAccountNotificationRead(token: string, id: string) {
    return request<{ id: string; readAt: string }>(`/account/notifications/${encodeURIComponent(id)}/read`, {
      method: 'POST',
      headers: bearer(token),
    })
  },
  markAllAccountNotificationsRead(token: string, payload: { category?: string } = {}) {
    return request<{ readCount: number }>('/account/notifications/read-all', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountNotificationPreferences(token: string) {
    return request<BackendNotificationPreferences>('/account/notification-preferences', { headers: bearer(token) })
  },
  updateAccountNotificationPreferences(token: string, payload: Partial<BackendNotificationPreferences>) {
    return request<BackendNotificationPreferences>('/account/notification-preferences', {
      method: 'PATCH',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  updateProfile(token: string, patch: Record<string, unknown>) {
    return request<BackendUser>('/account/profile', {
      method: 'PATCH',
      headers: bearer(token),
      body: JSON.stringify(patch),
    })
  },
  bindWechat(token: string, wechatId: string) {
    return request<BackendUser>('/account/wechat', {
      method: 'PATCH',
      headers: bearer(token),
      body: JSON.stringify({ wechatId }),
    })
  },
  passportVerification(passportNo: string) {
    return request<BackendPassportVerification>(`/passports/${encodeURIComponent(passportNo)}`)
  },
  completeOnboarding(token: string, payload: Record<string, unknown>) {
    return request<BackendUser>('/account/onboarding', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  products(type = '') {
    return request<{ items: BackendProduct[] }>(`/products${type ? `?type=${type}` : ''}`)
  },
  membershipCatalog() {
    return request<BackendMembershipCatalog>('/membership/catalog')
  },
  agentCatalog() {
    return request<BackendAgentCatalog>('/agents/catalog').then((catalog) => ({
      ...catalog,
      workflow: catalog.workflow ? { ...catalog.workflow, imageUrl: assetUrl(catalog.workflow.imageUrl) } : null,
      items: catalog.items.map(normalizeAgentProduct),
    }))
  },
  siteHome() {
    return request<BackendSiteHome>('/site/home').then(normalizeSiteHome)
  },
  dataServicePage() {
    return request<BackendDataServicePage>('/data-service/page').then((page) => ({
      blocks: (page.blocks || []).map((block) => ({
        ...block,
        items: (block.items || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
      })),
      assets: (page.assets || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    }))
  },
  adminSiteHome() {
    return request<BackendSiteHome>('/admin/site/home', { headers: adminHeaders() }).then(normalizeSiteHome)
  },
  siteRecommendations(placements: BackendRecommendationPlacement[]) {
    const query = new URLSearchParams()
    if (placements.length) query.set('placements', placements.join(','))
    return request<BackendRecommendationResponse>(`/site/recommendations${query.toString() ? `?${query}` : ''}`).then(normalizeRecommendationResponse)
  },
  adminRecommendationSlots(placements: BackendRecommendationPlacement[] = []) {
    const query = new URLSearchParams()
    if (placements.length) query.set('placements', placements.join(','))
    return request<BackendRecommendationResponse>(`/admin/site/recommendation-slots${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() }).then(normalizeRecommendationResponse)
  },
  saveAdminRecommendationSlots(slots: BackendRecommendationSlot[]) {
    return request<BackendRecommendationResponse>('/admin/site/recommendation-slots', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ slots }),
    }).then(normalizeRecommendationResponse)
  },
  adminRecommendationCandidates(params: { sourceType: BackendRecommendationSourceType; keyword?: string; status?: string }) {
    const query = new URLSearchParams()
    query.set('sourceType', params.sourceType)
    if (params.keyword) query.set('keyword', params.keyword)
    query.set('status', params.status || 'published')
    return request<{ items: BackendRecommendationCandidate[] }>(`/admin/site/recommendation-candidates?${query}`, { headers: adminHeaders() }).then((result) => ({
      items: result.items.map((item) => ({
        ...item,
        imageUrl: assetUrl(item.imageUrl),
        source: normalizeRecommendationSource(item.sourceType, item.source),
      })),
    }))
  },
  adminDataServicePage() {
    return request<BackendDataServicePage>('/admin/data-service/page', { headers: adminHeaders() }).then((page) => ({
      blocks: (page.blocks || []).map((block) => ({
        ...block,
        items: (block.items || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
      })),
      assets: (page.assets || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    }))
  },
  saveAdminDataServicePage(payload: BackendDataServicePage) {
    return request<BackendDataServicePage>('/admin/data-service/page', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then((page) => ({
      blocks: (page.blocks || []).map((block) => ({
        ...block,
        items: (block.items || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
      })),
      assets: (page.assets || []).map((item) => ({ ...item, imageUrl: assetUrl(item.imageUrl) })),
    }))
  },
  saveAdminSiteHome(payload: BackendSiteHome) {
    return request<BackendSiteHome>('/admin/site/home', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeSiteHome)
  },
  siteAbout() {
    return request<BackendSiteAbout>('/site/about').then(normalizeSiteAbout)
  },
  adminSiteAbout() {
    return request<BackendSiteAbout>('/admin/site/about', { headers: adminHeaders() }).then(normalizeSiteAbout)
  },
  saveAdminSiteAbout(payload: BackendSiteAbout) {
    return request<BackendSiteAbout>('/admin/site/about', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeSiteAbout)
  },
  siteConsulting() {
    return request<BackendSiteConsulting>('/site/consulting').then(normalizeSiteConsulting)
  },
  adminSiteConsulting() {
    return request<BackendSiteConsulting>('/admin/site/consulting', { headers: adminHeaders() }).then(normalizeSiteConsulting)
  },
  saveAdminSiteConsulting(payload: BackendSiteConsulting) {
    return request<BackendSiteConsulting>('/admin/site/consulting', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeSiteConsulting)
  },
  dataCatalog() {
    return request<{ items: BackendDataProduct[] }>('/data/catalog').then((result) => ({ items: result.items.map(normalizeDataProduct) }))
  },
  dataProduct(slug: string) {
    return request<BackendDataProduct>(`/data/catalog/${encodeURIComponent(slug)}`).then(normalizeDataProduct)
  },
  dataServiceOptions() {
    return request<{ optionSets: BackendConsultingOptionSet[] }>('/data-service/options')
  },
  agentProduct(slug: string) {
    return request<BackendAgentProduct>(`/agents/catalog/${encodeURIComponent(slug)}`).then(normalizeAgentProduct)
  },
  courseCatalog() {
    return request<BackendCourseCatalog>('/courses/catalog').then((catalog) => ({
      ...catalog,
      items: catalog.items.map(normalizeCourseProduct),
    }))
  },
  courseProduct(slug: string) {
    return request<BackendCourseProduct>(`/courses/catalog/${encodeURIComponent(slug)}`).then(normalizeCourseProduct)
  },
  eventCatalog() {
    return request<BackendEventCatalog>('/events/catalog').then((catalog) => ({
      ...catalog,
      items: catalog.items.map(normalizeEventProduct),
    }))
  },
  eventProduct(slug: string) {
    return request<BackendEventProduct>(`/events/catalog/${encodeURIComponent(slug)}`).then(normalizeEventProduct)
  },
  news(category = '') {
    return request<{ items: BackendNewsArticle[] }>(`/news${category ? `?category=${encodeURIComponent(category)}` : ''}`).then((result) => ({
      items: result.items.map(normalizeNewsArticle) as BackendNewsArticle[],
    }))
  },
  newsCategories() {
    return request<{ items: BackendNewsCategory[] }>('/news-categories')
  },
  newsDetail(slug: string) {
    return request<BackendNewsArticle>(`/news/${encodeURIComponent(slug)}`).then(normalizeNewsArticle)
  },
  experts(filters: { specialty?: string; direction?: string; search?: string; available?: boolean } = {}) {
    const query = new URLSearchParams()
    if (filters.specialty) query.set('specialty', filters.specialty)
    if (filters.direction) query.set('direction', filters.direction)
    if (filters.search) query.set('search', filters.search)
    if (filters.available) query.set('available', '1')
    return request<{ items: BackendExpert[] }>(`/experts${query.toString() ? `?${query}` : ''}`)
  },
  expertDirections() {
    return request<{ items: BackendExpertDirection[] }>('/expert-directions')
  },
  expertDetail(slug: string) {
    return request<BackendExpert>(`/experts/${encodeURIComponent(slug)}`)
  },
  expertSlots(slug: string, status = '') {
    return request<{ items: BackendExpertSlot[] }>(`/experts/${encodeURIComponent(slug)}/slots${status ? `?status=${encodeURIComponent(status)}` : ''}`)
  },
  siteAgreement(id = 'expert-cooperation-rules') {
    return request<BackendSiteAgreement>(`/site/agreements/${encodeURIComponent(id)}`)
  },
  accountExpertApplication(token: string) {
    return request<BackendExpertApplication | null>('/account/expert-application', { headers: bearer(token) })
  },
  submitExpertApplication(token: string, payload: Record<string, unknown>) {
    return request<BackendExpertApplication>('/account/expert-application', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountExpertProfile(token: string) {
    return request<BackendExpert | null>('/account/expert-profile', { headers: bearer(token) })
  },
  setAccountExpertAccepting(token: string, accepting: boolean) {
    return request<BackendExpert>('/account/expert-profile/accepting', {
      method: 'PATCH',
      headers: bearer(token),
      body: JSON.stringify({ accepting }),
    })
  },
  createExpertBooking(token: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>('/account/expert-bookings', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountExpertBookings(token: string) {
    return request<{ items: BackendExpertBooking[] }>('/account/expert-bookings', { headers: bearer(token) })
  },
  accountExpertBooking(token: string, id: string) {
    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}`, { headers: bearer(token) })
  },
  updateAccountExpertBooking(token: string, id: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  confirmAccountExpertBookingCompletion(token: string, id: string) {
    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/confirm-completion`, {
      method: 'POST',
      headers: bearer(token),
    })
  },
  disputeAccountExpertBookingCompletion(token: string, id: string, reason: string) {
    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/dispute`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify({ reason }),
    })
  },
  createAccountExpertBookingReschedule(token: string, id: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/reschedules`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  respondAccountExpertBookingReschedule(token: string, id: string, changeId: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/reschedules/${encodeURIComponent(changeId)}`, {
      method: 'PATCH',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountExpertSlots(token: string, filters: { from?: string; to?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    return request<{ items: BackendExpertSlot[] }>(`/account/expert-slots${query.toString() ? `?${query}` : ''}`, { headers: bearer(token) })
  },
  saveAccountExpertSlot(token: string, payload: Partial<BackendExpertSlot>) {
    return request<BackendExpertSlot>('/account/expert-slots', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountExpertWithdrawals(token: string) {
    return request<{ items: BackendExpertWithdrawal[] }>('/account/expert-withdrawals', { headers: bearer(token) })
  },
  accountExpertWallet(token: string) {
    return request<BackendExpertWallet>('/account/expert-wallet', { headers: bearer(token) })
  },
  createExpertWithdrawal(token: string, payload: Record<string, unknown>) {
    return request<BackendExpertWithdrawal>('/account/expert-withdrawals', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  previewCheckout(token: string, items: CartItem[], couponCode?: string) {
    return request<BackendCheckoutPreview>('/checkout/preview', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify({
        items: items.map(checkoutItemPayload),
        couponCode,
      }),
    })
  },
  createOrder(token: string, items: CartItem[], couponCode?: string, expertBookingId?: string, dataServiceRequestId?: string, consultingRequestId?: string, invoiceRequest?: BackendInvoiceRequest) {
    return request<BackendOrder>('/orders', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify({
        items: items.map(checkoutItemPayload),
        couponCode,
        expertBookingId,
        dataServiceRequestId,
        consultingRequestId,
        invoiceRequest,
      }),
    })
  },
  createPaymentOrder(token: string, orderNo: string, channel: BackendPaymentChannel = defaultPaymentChannel) {
    return request<{ paymentOrder: BackendPaymentOrder; order: BackendOrder }>('/payment-orders', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify({ orderNo, channel }),
    })
  },
  paymentStatus(token: string, paymentNo: string) {
    return request<{ paymentOrder: BackendPaymentOrder; order: BackendOrder; canRedirect: boolean }>(`/payment-orders/${encodeURIComponent(paymentNo)}/status`, {
      headers: bearer(token),
    })
  },
  cancelPaymentOrder(token: string, paymentNo: string) {
    return request<{ paymentOrder: BackendPaymentOrder; order: BackendOrder; canRedirect: boolean }>(`/payment-orders/${encodeURIComponent(paymentNo)}/cancel`, {
      method: 'POST',
      headers: bearer(token),
    })
  },
  succeedDevPayment(paymentNo: string) {
    return request<{ order: BackendOrder }>(`/dev/payment-orders/${paymentNo}/succeed`, {
      method: 'POST',
      headers: adminOrDevTokenHeaders(),
    })
  },
  accountOrders(token: string) {
    return request<{ items: BackendOrder[] }>('/account/orders', { headers: bearer(token) })
  },
  accountOrder(token: string, orderNo: string) {
    return request<BackendOrder>(`/account/orders/${encodeURIComponent(orderNo)}`, { headers: bearer(token) })
  },
  createAccountInvoiceApplication(token: string, orderNo: string, payload: { title: string; taxNumber?: string; email: string; remark?: string }) {
    return request<BackendInvoiceApplication>(`/account/orders/${encodeURIComponent(orderNo)}/invoice-application`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountInvoiceApplications(token: string, filters: { status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendInvoiceApplication[] }>(`/account/invoice-applications${query.toString() ? `?${query}` : ''}`, { headers: bearer(token) })
  },
  accountInvoiceApplication(token: string, invoiceNo: string) {
    return request<BackendInvoiceApplication>(`/account/invoice-applications/${encodeURIComponent(invoiceNo)}`, { headers: bearer(token) })
  },
  async downloadAccountInvoiceFile(token: string, invoiceNo: string) {
    const response = await fetch(`${apiBase}/account/invoice-applications/${encodeURIComponent(invoiceNo)}/file`, { headers: bearer(token) })
    if (!response.ok) throw new Error(await response.text() || '发票文件下载失败')
    return response.blob()
  },
  accountDataProducts(token: string) {
    return request<{ items: BackendDataProduct[] }>('/account/data-products', { headers: bearer(token) }).then((result) => ({ items: result.items.map(normalizeDataProduct) }))
  },
  createDataServiceRequest(token: string, payload: unknown) {
    return request<BackendDataServiceRequest>('/data-service-requests', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    }).then(normalizeDataServiceRequest)
  },
  accountDataServiceRequests(token: string) {
    return request<{ items: BackendDataServiceRequest[] }>('/account/data-service-requests', { headers: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeDataServiceRequest) }))
  },
  accountDataServiceRequest(token: string, id: string) {
    return request<BackendDataServiceRequest>(`/account/data-service-requests/${encodeURIComponent(id)}`, { headers: bearer(token) }).then(normalizeDataServiceRequest)
  },
  createDataServiceCheckout(token: string, id: string, invoiceRequest?: BackendInvoiceRequest) {
    return request<BackendOrder>(`/account/data-service-requests/${encodeURIComponent(id)}/checkout`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify({ invoiceRequest }),
    })
  },
  createConsultingCheckout(token: string, id: string, invoiceRequest?: BackendInvoiceRequest) {
    return request<BackendOrder>(`/account/consulting-requests/${encodeURIComponent(id)}/checkout`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify({ invoiceRequest }),
    })
  },
  accountCourseRegistrations(token: string) {
    return request<{ items: BackendCourseRegistration[] }>('/account/course-registrations', { headers: bearer(token) }).then((result) => ({ items: result.items.map(normalizeCourseRegistration) }))
  },
  accountCourseRegistration(token: string, id: string) {
    return request<BackendCourseRegistration>(`/account/course-registrations/${encodeURIComponent(id)}`, { headers: bearer(token) }).then(normalizeCourseRegistration)
  },
  accountEventRegistrations(token: string) {
    return request<{ items: BackendEventRegistration[] }>('/account/event-registrations', { headers: bearer(token) }).then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  accountEventRegistration(token: string, id: string) {
    return request<BackendEventRegistration>(`/account/event-registrations/${encodeURIComponent(id)}`, { headers: bearer(token) }).then(normalizeEventRegistration)
  },
  accountTasks(token: string) {
    return request<{ items: BackendTask[] }>('/account/tasks', { headers: bearer(token) })
  },
  accountTask(token: string, id: string) {
    return request<BackendTask>(`/account/tasks/${encodeURIComponent(id)}`, { headers: bearer(token) })
  },
  createConsultingRequest(token: string, payload: unknown) {
    return request<BackendConsultingRequest>('/consulting-requests', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  createCooperationRequest(token: string, payload: unknown) {
    return request<BackendCooperationRequest>('/cooperation-requests', {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  accountConsultingRequests(token: string) {
    return request<{ items: BackendConsultingRequest[] }>('/account/consulting-requests', { headers: bearer(token) })
  },
  submitAccountTaskMaterials(token: string, id: string, payload: Record<string, unknown>) {
    return request<BackendTask>(`/account/tasks/${encodeURIComponent(id)}/materials`, {
      method: 'POST',
      headers: bearer(token),
      body: JSON.stringify(payload),
    })
  },
  adminOrders(filters: { search?: string; status?: string; from?: string; to?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.status) query.set('status', filters.status)
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    return request<{ items: BackendOrder[] }>(`/admin/orders${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminOrder(id: string) {
    return request<BackendOrder>(`/admin/orders/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  adminPayments(filters: { search?: string; status?: string; from?: string; to?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.status) query.set('status', filters.status)
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    return request<{ items: BackendPaymentOrder[] }>(`/admin/payments${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminDashboardSummary(filters: { range?: 'today' | '7d' | '30d' | string } = {}) {
    const query = new URLSearchParams()
    if (filters.range) query.set('range', filters.range)
    return request<BackendAdminDashboardSummary>(`/admin/dashboard/summary${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminOperationalEvents(filters: { q?: string; search?: string; status?: string; severity?: string; type?: string; page?: number | string } = {}) {
    const query = new URLSearchParams()
    if (filters.q || filters.search) query.set('q', String(filters.q || filters.search))
    if (filters.status) query.set('status', filters.status)
    if (filters.severity) query.set('severity', filters.severity)
    if (filters.type) query.set('type', filters.type)
    if (filters.page) query.set('page', String(filters.page))
    return request<BackendOperationalEventList>(`/admin/exceptions${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminOperationalEvent(id: string) {
    return request<BackendOperationalEvent>(`/admin/exceptions/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  updateAdminOperationalEvent(id: string, payload: { status: BackendOperationalEventStatus; note?: string }) {
    return request<BackendOperationalEvent>(`/admin/exceptions/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  retryAdminOperationalEvent(id: string, payload: { note?: string } = {}) {
    return request<{ event: BackendOperationalEvent; retry: BackendOperationalEvent }>(`/admin/exceptions/${encodeURIComponent(id)}/retry`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  resolveAdminOperationalEvent(id: string, payload: { note?: string; status?: 'resolved' | 'ignored' } = {}) {
    return request<BackendOperationalEvent>(`/admin/exceptions/${encodeURIComponent(id)}/resolve`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminInvoiceApplications(filters: { q?: string; search?: string; status?: string; from?: string; to?: string; page?: number | string } = {}) {
    const query = new URLSearchParams()
    if (filters.q || filters.search) query.set('q', String(filters.q || filters.search))
    if (filters.status) query.set('status', filters.status)
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    if (filters.page) query.set('page', String(filters.page))
    return request<{ items: BackendInvoiceApplication[]; page: number; pageSize: number; total: number }>(`/admin/invoice-applications${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminInvoiceApplication(invoiceNo: string) {
    return request<BackendInvoiceApplication>(`/admin/invoice-applications/${encodeURIComponent(invoiceNo)}`, { headers: adminHeaders() })
  },
  updateAdminInvoiceApplication(invoiceNo: string, payload: Partial<BackendInvoiceApplication> & Record<string, unknown>) {
    return request<BackendInvoiceApplication>(`/admin/invoice-applications/${encodeURIComponent(invoiceNo)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  async downloadAdminInvoiceFile(invoiceNo: string) {
    const response = await fetch(`${apiBase}/admin/invoice-applications/${encodeURIComponent(invoiceNo)}/file`, { headers: adminHeaders() })
    if (!response.ok) throw new Error(await response.text() || '发票文件下载失败')
    return response.blob()
  },
  adminInvoiceApplicationsExportUrl(filters: { q?: string; search?: string; status?: string; from?: string; to?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.q || filters.search) query.set('q', String(filters.q || filters.search))
    if (filters.status) query.set('status', filters.status)
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    return `${apiBase}/admin/invoice-applications/export${query.toString() ? `?${query}` : ''}`
  },
  async adminInvoiceApplicationsCsv(filters: { q?: string; search?: string; status?: string; from?: string; to?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.q || filters.search) query.set('q', String(filters.q || filters.search))
    if (filters.status) query.set('status', filters.status)
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    const response = await fetch(`${apiBase}/admin/invoice-applications/export${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
    if (!response.ok) throw new Error(await response.text() || '发票导出失败')
    return response.blob()
  },
  adminRevenue(filters: { from?: string; to?: string; type?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    if (filters.type) query.set('type', filters.type)
    if (filters.status) query.set('status', filters.status)
    return request<BackendRevenueReport>(`/admin/revenue${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminReconcile(filters: { from?: string; to?: string; search?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    if (filters.search) query.set('search', filters.search)
    return request<{ items: BackendReconcileRow[] }>(`/admin/reconcile${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminReconcileExportUrl(filters: { from?: string; to?: string; search?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    if (filters.search) query.set('search', filters.search)
    return `${apiBase}/admin/reconcile/export${query.toString() ? `?${query}` : ''}`
  },
  staffOrders() {
    return request<{ items: BackendOrder[] }>('/staff/orders', { headers: adminHeaders() })
  },
  adminStaffAccounts(filters: { search?: string; status?: string; role?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.status) query.set('status', filters.status)
    if (filters.role) query.set('role', filters.role)
    return request<{ items: BackendStaffAccount[] }>(`/admin/staff-accounts${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminStaffAccount(id: string) {
    return request<BackendStaffAccount>(`/admin/staff-accounts/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  adminStaffEffectivePermissions(id: string) {
    return request<BackendStaffEffectivePermissions>(`/admin/staff-accounts/${encodeURIComponent(id)}/effective-permissions`, { headers: adminHeaders() })
  },
  saveAdminStaffDirectPermissions(id: string, permissions: string[]) {
    return request<BackendStaffEffectivePermissions>(`/admin/staff-accounts/${encodeURIComponent(id)}/direct-permissions`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ permissions }),
    })
  },
  createAdminStaffAccount(payload: Partial<BackendStaffAccount> & Record<string, unknown>) {
    return request<BackendStaffAccount>('/admin/staff-accounts', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminStaffAccount(id: string, payload: Partial<BackendStaffAccount> & Record<string, unknown>) {
    return request<BackendStaffAccount>(`/admin/staff-accounts/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  disableAdminStaffAccount(id: string) {
    return request<BackendStaffAccount>(`/admin/staff-accounts/${encodeURIComponent(id)}/disable`, {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  enableAdminStaffAccount(id: string) {
    return request<BackendStaffAccount>(`/admin/staff-accounts/${encodeURIComponent(id)}/enable`, {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  adminStaffRoles() {
    return request<{ items: BackendStaffRole[] }>('/admin/staff-roles', { headers: adminHeaders() })
  },
  adminStaffRole(code: string) {
    return request<BackendStaffRole>(`/admin/staff-roles/${encodeURIComponent(code)}`, { headers: adminHeaders() })
  },
  adminStaffRoleAccounts(code: string) {
    return request<{ items: BackendStaffAccount[] }>(`/admin/staff-roles/${encodeURIComponent(code)}/accounts`, { headers: adminHeaders() })
  },
  updateAdminStaffRole(code: string, payload: Partial<BackendStaffRole> & Record<string, unknown>) {
    return request<BackendStaffRole>(`/admin/staff-roles/${encodeURIComponent(code)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminPermissionCatalog() {
    return request<{ items: BackendPermissionItem[] }>('/admin/permission-catalog', { headers: adminHeaders() })
  },
  adminOrgTree() {
    return request<BackendOrgTree>('/admin/org-tree', { headers: adminHeaders() })
  },
  createAdminOrgUnit(payload: Record<string, unknown>) {
    return request<BackendOrgTree>('/admin/org-units', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminOrgUnit(id: string, payload: Record<string, unknown>) {
    return request<BackendOrgTree>(`/admin/org-units/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminOrgUnitPermissions(id: string, permissions: string[]) {
    return request<BackendOrgTree>(`/admin/org-units/${encodeURIComponent(id)}/permissions`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ permissions }),
    })
  },
  createAdminPosition(payload: Record<string, unknown>) {
    return request<BackendOrgTree>('/admin/positions', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminPosition(id: string, payload: Record<string, unknown>) {
    return request<BackendOrgTree>(`/admin/positions/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminPositionPermissions(id: string, permissions: string[]) {
    return request<BackendOrgTree>(`/admin/positions/${encodeURIComponent(id)}/permissions`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ permissions }),
    })
  },
  adminStaffAssignments() {
    return request<{ items: BackendStaffAssignment[] }>('/admin/staff-assignments', { headers: adminHeaders() })
  },
  createAdminStaffAssignment(payload: Record<string, unknown>) {
    return request<{ items: BackendStaffAssignment[] }>('/admin/staff-assignments', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminStaffAssignment(accountId: string, assignmentId: string, payload: Record<string, unknown>) {
    return request<{ items: BackendStaffAssignment[] }>(`/admin/staff-accounts/${encodeURIComponent(accountId)}/assignments/${encodeURIComponent(assignmentId)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  deleteAdminStaffAssignment(accountId: string, assignmentId: string) {
    return request<{ items: BackendStaffAssignment[] }>(`/admin/staff-accounts/${encodeURIComponent(accountId)}/assignments/${encodeURIComponent(assignmentId)}`, {
      method: 'DELETE',
      headers: adminHeaders(),
    })
  },
  adminStaffAuditLogs(filters: { search?: string; action?: string; source?: string; targetType?: string; dateFrom?: string; dateTo?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.action) query.set('action', filters.action)
    if (filters.source) query.set('source', filters.source)
    if (filters.targetType) query.set('targetType', filters.targetType)
    if (filters.dateFrom) query.set('dateFrom', filters.dateFrom)
    if (filters.dateTo) query.set('dateTo', filters.dateTo)
    return request<{ items: BackendStaffAuditLog[] }>(`/admin/staff-audit-logs${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  businessSearch(query: string) {
    return request<{ items: BackendBusinessSearchResult[] }>(`/admin/business-search?q=${encodeURIComponent(query)}`, { headers: adminHeaders() })
  },
  adminCooperationRequests(status = '') {
    return request<{ items: BackendCooperationRequest[] }>(`/admin/cooperation-requests${status ? `?status=${status}` : ''}`, { headers: adminHeaders() })
  },
  adminCooperationRequest(id: string) {
    return request<BackendCooperationRequest>(`/admin/cooperation-requests/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  updateCooperationRequest(id: string, payload: Record<string, unknown>) {
    return request<BackendCooperationRequest>(`/admin/cooperation-requests/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  completeCooperationRequest(id: string) {
    return request<BackendCooperationRequest>(`/admin/cooperation-requests/${encodeURIComponent(id)}/complete`, {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  convertCooperationRequest(id: string, payload: Record<string, unknown>) {
    return request<{ cooperation: BackendCooperationRequest; target: { id: string; requestNo: string; type: string } }>(`/admin/cooperation-requests/${encodeURIComponent(id)}/convert`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminProducts(params: { includeServiceTypes?: boolean } = {}) {
    const search = new URLSearchParams()
    if (params.includeServiceTypes) search.set('includeServiceTypes', 'true')
    return request<{ items: BackendProduct[] }>(`/admin/products${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
  },
  adminUsers(filters: { search?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendAdminUser[] }>(`/admin/users${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminUser(id: string) {
    return request<BackendAdminUserDetail>(`/admin/users/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  adminMemberships(filters: { search?: string; tier?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.tier) query.set('tier', filters.tier)
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendMembershipSubscription[] }>(`/admin/memberships${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  manualGrantMembership(payload: { userId?: string; passportNo?: string; phone?: string; tier: 'junior' | 'senior'; durationDays: number }) {
    return request<BackendMembershipSubscription>('/admin/memberships/manual-grant', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminMembership(subscriptionId: string, payload: {
    tier?: 'junior' | 'senior'
    status?: BackendMembershipSubscription['status']
    startsAt?: string
    expiresAt?: string
    reason: string
  }) {
    return request<BackendMembershipSubscription>(`/admin/memberships/${encodeURIComponent(subscriptionId)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  cancelAdminMembership(subscriptionId: string, payload: { mode?: 'period_end' | 'immediate'; reason?: string } = {}) {
    return request<BackendMembershipSubscription>(`/admin/memberships/${encodeURIComponent(subscriptionId)}/cancel`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  assignMembershipManager(subscriptionId: string, payload: { staffAccountId: string; note?: string }) {
    return request<BackendMembershipServiceAssignment>(`/admin/memberships/${encodeURIComponent(subscriptionId)}/assign-manager`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  runMembershipExpiryJob() {
    return request<{ expiredCount: number; downgradedCount: number }>('/admin/memberships/jobs/expire', {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  runMembershipExpiryReminderJob() {
    return request<{ queuedCount: number }>('/admin/memberships/jobs/expiry-reminders', {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  runMembershipWinbackReminderJob() {
    return request<{ queuedCount: number }>('/admin/memberships/jobs/winback-reminders', {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  adminNotifications(filters: { scene?: string; status?: string; category?: string; channel?: string; batchId?: string; page?: number; pageSize?: number } = {}) {
    const query = new URLSearchParams()
    if (filters.scene) query.set('scene', filters.scene)
    if (filters.status) query.set('status', filters.status)
    if (filters.category) query.set('category', filters.category)
    if (filters.channel) query.set('channel', filters.channel)
    if (filters.batchId) query.set('batchId', filters.batchId)
    if (filters.page) query.set('page', String(filters.page))
    if (filters.pageSize) query.set('pageSize', String(filters.pageSize))
    return request<BackendNotificationListResponse>(`/admin/notifications${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  dispatchNotifications() {
    return request<{ sentCount: number; skippedCount: number }>('/admin/notifications/dispatch', {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  retryNotification(id: string) {
    return request<BackendNotification>(`/admin/notifications/${encodeURIComponent(id)}/retry`, {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  adminNotificationTemplates(filters: { search?: string; scene?: string; category?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.scene) query.set('scene', filters.scene)
    if (filters.category) query.set('category', filters.category)
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendNotificationTemplate[] }>(`/admin/notification-templates${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  updateNotificationTemplate(templateKey: string, payload: Partial<BackendNotificationTemplate>) {
    return request<BackendNotificationTemplate>(`/admin/notification-templates/${encodeURIComponent(templateKey)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminNotificationBatches(filters: { search?: string; status?: string; page?: number; pageSize?: number } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.status) query.set('status', filters.status)
    if (filters.page) query.set('page', String(filters.page))
    if (filters.pageSize) query.set('pageSize', String(filters.pageSize))
    return request<{ items: BackendNotificationBatch[]; page: number; pageSize: number; total: number }>(`/admin/notification-batches${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  createNotificationBatch(payload: {
    title: string
    body: string
    actionUrl?: string
    targetType: BackendNotificationTargetType
    targetFilters?: Record<string, unknown>
    channels?: string[]
    priority?: string
    scheduledAt?: string
    sendNow?: boolean
  }) {
    return request<BackendNotificationBatch>('/admin/notification-batches', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminNotificationBatch(id: string) {
    return request<BackendNotificationBatch>(`/admin/notification-batches/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  sendNotificationBatch(id: string) {
    return request<BackendNotificationBatch>(`/admin/notification-batches/${encodeURIComponent(id)}/send`, {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  createAdminUser(payload: Partial<BackendAdminUser> & Record<string, unknown>) {
    return request<BackendAdminUser>('/admin/users', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminUser(id: string, payload: Partial<BackendAdminUser> & Record<string, unknown>) {
    return request<BackendAdminUser>(`/admin/users/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminMembershipPlans() {
    return request<{ items: BackendMembershipPlan[] }>('/admin/membership/plans', { headers: adminHeaders() })
  },
  adminMembershipCatalog() {
    return request<BackendMembershipCatalog>('/admin/membership/catalog', { headers: adminHeaders() })
  },
  adminMembershipBenefits() {
    return request<{ items: BackendMembershipBenefit[] }>('/admin/membership/benefits', { headers: adminHeaders() })
  },
  saveAdminMembershipBenefit(code: string | null, payload: Record<string, unknown>) {
    return request<BackendMembershipBenefit>(code ? `/admin/membership/benefits/${encodeURIComponent(code)}` : '/admin/membership/benefits', {
      method: code ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  saveAdminMembershipPlanBenefits(productId: string, benefits: BackendMembershipPlanBenefit[]) {
    return request<{ productId: string; benefits: BackendMembershipPlanBenefit[] }>(`/admin/membership/plans/${encodeURIComponent(productId)}/benefits`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ benefits }),
    })
  },
  adminMembershipEntitlements(filters: { search?: string; benefitCode?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.search) query.set('search', filters.search)
    if (filters.benefitCode) query.set('benefitCode', filters.benefitCode)
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendMembershipEntitlementAccount[] }>(`/admin/membership/entitlements${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  adminPassportVerify(queryText: string) {
    return request<BackendAdminPassportVerification>(`/admin/passports/verify?q=${encodeURIComponent(queryText)}`, { headers: adminHeaders() })
  },
  adjustAdminMembershipEntitlement(id: string, payload: { delta?: number; quotaTotal?: number; note?: string }) {
    return request<BackendMembershipEntitlementAccount>(`/admin/membership/entitlements/${encodeURIComponent(id)}/adjust`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminMembershipContentDeliveries(filters: { status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendMembershipContentDelivery[] }>(`/admin/membership/content-deliveries${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  saveAdminMembershipContentDelivery(id: string | null, payload: Record<string, unknown>) {
    return request<BackendMembershipContentDelivery>(id ? `/admin/membership/content-deliveries/${encodeURIComponent(id)}` : '/admin/membership/content-deliveries', {
      method: id ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  saveAdminMembershipPlan(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendMembershipPlan>(productId ? `/admin/membership/plans/${encodeURIComponent(productId)}` : '/admin/membership/plans', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminAgentProducts() {
    return request<{ items: BackendAgentProduct[] }>('/admin/agent-products', { headers: adminHeaders() })
  },
  saveAdminAgentProduct(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendAgentProduct>(productId ? `/admin/agent-products/${encodeURIComponent(productId)}` : '/admin/agent-products', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  publishAgentProduct(id: string) {
    return request<BackendAgentProduct>(`/admin/agent-products/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() })
  },
  offlineAgentProduct(id: string) {
    return request<BackendAgentProduct>(`/admin/agent-products/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() })
  },
  draftAgentProduct(id: string) {
    return request<BackendAgentProduct>(`/admin/agent-products/${encodeURIComponent(id)}/draft`, { method: 'POST', headers: adminHeaders() })
  },
  deleteAgentProduct(id: string) {
    return request<{ ok: boolean }>(`/admin/agent-products/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  adminDataProducts() {
    return request<{ items: BackendDataProduct[] }>('/admin/data-products', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeDataProduct) }))
  },
  adminDataCases() {
    return request<{ items: BackendDataProduct[] }>('/admin/data-cases', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeDataProduct) }))
  },
  adminDataServiceCases() {
    return request<{ items: BackendDataServiceCase[] }>('/admin/data-service/cases', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeDataProduct) as BackendDataServiceCase[] }))
  },
  saveAdminDataProduct(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendDataProduct>(productId ? `/admin/data-products/${encodeURIComponent(productId)}` : '/admin/data-products', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeDataProduct)
  },
  saveAdminDataCase(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendDataProduct>(productId ? `/admin/data-cases/${encodeURIComponent(productId)}` : '/admin/data-cases', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeDataProduct)
  },
  saveAdminDataServiceCase(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendDataServiceCase>(productId ? `/admin/data-service/cases/${encodeURIComponent(productId)}` : '/admin/data-service/cases', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then((item) => normalizeDataProduct(item) as BackendDataServiceCase)
  },
  publishDataProduct(id: string) {
    return request<BackendDataProduct>(`/admin/data-products/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() }).then(normalizeDataProduct)
  },
  publishDataCase(id: string) {
    return request<BackendDataProduct>(`/admin/data-cases/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() }).then(normalizeDataProduct)
  },
  publishDataServiceCase(id: string) {
    return request<BackendDataServiceCase>(`/admin/data-service/cases/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() }).then((item) => normalizeDataProduct(item) as BackendDataServiceCase)
  },
  offlineDataProduct(id: string) {
    return request<BackendDataProduct>(`/admin/data-products/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() }).then(normalizeDataProduct)
  },
  offlineDataCase(id: string) {
    return request<BackendDataProduct>(`/admin/data-cases/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() }).then(normalizeDataProduct)
  },
  offlineDataServiceCase(id: string) {
    return request<BackendDataServiceCase>(`/admin/data-service/cases/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() }).then((item) => normalizeDataProduct(item) as BackendDataServiceCase)
  },
  deleteDataProduct(id: string) {
    return request<{ ok: boolean }>(`/admin/data-products/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  deleteDataCase(id: string) {
    return request<{ ok: boolean }>(`/admin/data-cases/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  deleteDataServiceCase(id: string) {
    return request<{ ok: boolean }>(`/admin/data-service/cases/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  uploadAdminFile(file: File) {
    return request<{ id: string; fileName: string; mimeType: string; fileSize: number; url: string }>('/admin/uploads/raw', {
      method: 'POST',
      headers: { ...adminOrDevTokenHeaders(), 'x-file-name': encodeURIComponent(file.name), 'content-type': file.type || 'application/octet-stream' },
      body: file,
    })
  },
  uploadAdminInvoiceFile(invoiceNo: string, file: File) {
    return request<{ invoice: BackendInvoiceApplication; file: { id: string; fileName: string; mimeType: string; fileSize: number; url: string } }>(`/admin/invoice-applications/${encodeURIComponent(invoiceNo)}/file`, {
      method: 'POST',
      headers: { ...adminHeaders(), 'x-file-name': encodeURIComponent(file.name), 'content-type': file.type || 'application/octet-stream' },
      body: file,
    })
  },
  uploadAccountFile(token: string, file: File) {
    return request<{ id: string; fileName: string; mimeType: string; fileSize: number; url: string }>('/account/uploads/raw', {
      method: 'POST',
      headers: { ...bearer(token), 'x-file-name': encodeURIComponent(file.name), 'content-type': file.type || 'application/octet-stream' },
      body: file,
    })
  },
  uploadStaffFile(file: File) {
    return request<{ id: string; fileName: string; mimeType: string; fileSize: number; url: string }>('/staff/uploads/raw', {
      method: 'POST',
      headers: { ...adminHeaders(), 'x-file-name': encodeURIComponent(file.name), 'content-type': file.type || 'application/octet-stream' },
      body: file,
    })
  },
  adminCourseProducts() {
    return request<{ items: BackendCourseProduct[] }>('/admin/course-products', { headers: adminHeaders() })
  },
  saveAdminCourseProduct(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendCourseProduct>(productId ? `/admin/course-products/${encodeURIComponent(productId)}` : '/admin/course-products', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  publishCourseProduct(id: string) {
    return request<BackendCourseProduct>(`/admin/course-products/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() })
  },
  offlineCourseProduct(id: string) {
    return request<BackendCourseProduct>(`/admin/course-products/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() })
  },
  draftCourseProduct(id: string) {
    return request<BackendCourseProduct>(`/admin/course-products/${encodeURIComponent(id)}/draft`, { method: 'POST', headers: adminHeaders() })
  },
  deleteCourseProduct(id: string) {
    return request<{ ok: boolean }>(`/admin/course-products/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  adminCourseRegistrations(filters: { productId?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.productId) query.set('productId', filters.productId)
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendCourseRegistration[] }>(`/admin/course-registrations${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeCourseRegistration) }))
  },
  adminCourseProductRegistrations(productId: string, filters: { status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendCourseRegistration[] }>(`/admin/course-products/${encodeURIComponent(productId)}/registrations${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeCourseRegistration) }))
  },
  adminEventProducts() {
    return request<{ items: BackendEventProduct[] }>('/admin/event-products', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventProduct) }))
  },
  adminEvents() {
    return request<{ items: BackendEventProduct[] }>('/admin/events', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventProduct) }))
  },
  saveAdminEventProduct(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendEventProduct>(productId ? `/admin/event-products/${encodeURIComponent(productId)}` : '/admin/event-products', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  saveAdminEvent(productId: string | null, payload: Record<string, unknown>) {
    return request<BackendEventProduct>(productId ? `/admin/events/${encodeURIComponent(productId)}` : '/admin/events', {
      method: productId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventProduct)
  },
  publishEventProduct(id: string) {
    return request<BackendEventProduct>(`/admin/event-products/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() })
  },
  publishEvent(id: string) {
    return request<BackendEventProduct>(`/admin/events/${encodeURIComponent(id)}/publish`, { method: 'POST', headers: adminHeaders() }).then(normalizeEventProduct)
  },
  offlineEventProduct(id: string) {
    return request<BackendEventProduct>(`/admin/event-products/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() })
  },
  offlineEvent(id: string) {
    return request<BackendEventProduct>(`/admin/events/${encodeURIComponent(id)}/offline`, { method: 'POST', headers: adminHeaders() }).then(normalizeEventProduct)
  },
  draftEventProduct(id: string) {
    return request<BackendEventProduct>(`/admin/event-products/${encodeURIComponent(id)}/draft`, { method: 'POST', headers: adminHeaders() })
  },
  closeEventRegistration(id: string) {
    return request<BackendEventProduct>(`/admin/events/${encodeURIComponent(id)}/close-registration`, { method: 'POST', headers: adminHeaders() }).then(normalizeEventProduct)
  },
  deleteEventProduct(id: string) {
    return request<{ ok: boolean }>(`/admin/event-products/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  deleteEvent(id: string) {
    return request<{ ok: boolean }>(`/admin/events/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  adminEventRegistrations(filters: { productId?: string; status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.productId) query.set('productId', filters.productId)
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendEventRegistration[] }>(`/admin/event-registrations${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  adminEventProductRegistrations(productId: string, filters: { status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendEventRegistration[] }>(`/admin/event-products/${encodeURIComponent(productId)}/registrations${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  adminEventRegistrationsForEvent(productId: string, filters: { status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendEventRegistration[] }>(`/admin/events/${encodeURIComponent(productId)}/registrations${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  createAdminEventRegistrationForEvent(productId: string, payload: { passportNo?: string; phone?: string; note?: string; checkIn?: boolean; source?: string }) {
    return request<BackendEventRegistration>(`/admin/events/${encodeURIComponent(productId)}/registrations`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventRegistration)
  },
  updateAdminEventRegistration(id: string, payload: Record<string, unknown>) {
    return request<BackendEventRegistration>(`/admin/event-registrations/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventRegistration)
  },
  cancelAdminEventRegistration(id: string, payload: Record<string, unknown> = {}) {
    return request<BackendEventRegistration>(`/admin/event-registrations/${encodeURIComponent(id)}/cancel`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventRegistration)
  },
  adminNews() {
    return request<{ items: BackendNewsArticle[] }>('/admin/news', { headers: adminHeaders() }).then((result) => ({
      items: result.items.map(normalizeNewsArticle) as BackendNewsArticle[],
    }))
  },
  adminNewsCategories() {
    return request<{ items: BackendNewsCategory[] }>('/admin/news-categories', { headers: adminHeaders() })
  },
  createAdminNewsCategory(payload: Partial<BackendNewsCategory>) {
    return request<BackendNewsCategory>('/admin/news-categories', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminNewsCategory(code: string, payload: Partial<BackendNewsCategory>) {
    return request<BackendNewsCategory>(`/admin/news-categories/${encodeURIComponent(code)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  deleteAdminNewsCategory(code: string) {
    return request<{ ok: boolean; item?: BackendNewsCategory }>(`/admin/news-categories/${encodeURIComponent(code)}`, {
      method: 'DELETE',
      headers: adminHeaders(),
    })
  },
  adminExperts(filters: { status?: string; direction?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    if (filters.direction) query.set('direction', filters.direction)
    return request<{ items: BackendExpert[] }>(`/admin/experts${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() })
  },
  adminExpert(id: string) {
    return request<BackendExpert>(`/admin/experts/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  createAdminExpert(payload: Partial<BackendExpert> & Record<string, unknown>) {
    return request<BackendExpert>('/admin/experts', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminExpert(id: string, payload: Partial<BackendExpert> & Record<string, unknown>) {
    return request<BackendExpert>(`/admin/experts/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  deleteAdminExpert(id: string) {
    return request<{ ok: boolean }>(`/admin/experts/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  publishExpert(id: string) {
    return request<BackendExpert>(`/admin/experts/${id}/publish`, { method: 'POST', headers: adminHeaders() })
  },
  offlineExpert(id: string) {
    return request<BackendExpert>(`/admin/experts/${id}/offline`, { method: 'POST', headers: adminHeaders() })
  },
  adminExpertDirections() {
    return request<{ items: BackendExpertDirection[] }>('/admin/expert-directions', { headers: adminHeaders() })
  },
  createAdminExpertDirection(payload: Partial<BackendExpertDirection> & Record<string, unknown>) {
    return request<BackendExpertDirection>('/admin/expert-directions', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminExpertDirection(id: string, payload: Partial<BackendExpertDirection> & Record<string, unknown>) {
    return request<BackendExpertDirection>(`/admin/expert-directions/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  deleteAdminExpertDirection(id: string) {
    return request<{ ok: boolean }>(`/admin/expert-directions/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  adminExpertApplications(status = '') {
    return request<{ items: BackendExpertApplication[] }>(`/admin/expert-applications${status ? `?status=${encodeURIComponent(status)}` : ''}`, { headers: adminHeaders() })
  },
  reviewExpertApplication(id: string, payload: Record<string, unknown>) {
    return request<BackendExpertApplication>(`/admin/expert-applications/${encodeURIComponent(id)}/review`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminExpertBookings(filters: { status?: string; expertId?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    if (filters.expertId) query.set('expertId', filters.expertId)
    return request<{ items: BackendExpertBooking[] }>(`/admin/expert-bookings${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  updateAdminExpertBooking(id: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>(`/admin/expert-bookings/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  releaseExpiredExpertBookingHolds() {
    return request<{ ok: boolean }>('/admin/expert-bookings/release-expired', {
      method: 'POST',
      headers: adminHeaders(),
    })
  },
  createAdminExpertBookingReschedule(id: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>(`/admin/expert-bookings/${encodeURIComponent(id)}/reschedules`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  respondAdminExpertBookingReschedule(id: string, changeId: string, payload: Record<string, unknown>) {
    return request<BackendExpertBooking>(`/admin/expert-bookings/${encodeURIComponent(id)}/reschedules/${encodeURIComponent(changeId)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminExpertSlots(filters: { expertId?: string; from?: string; to?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.expertId) query.set('expertId', filters.expertId)
    if (filters.from) query.set('from', filters.from)
    if (filters.to) query.set('to', filters.to)
    return request<{ items: BackendExpertSlot[] }>(`/admin/expert-slots${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  saveAdminExpertSlot(payload: Partial<BackendExpertSlot>) {
    return request<BackendExpertSlot>('/admin/expert-slots', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminExpertWithdrawals(status = '') {
    return request<{ items: BackendExpertWithdrawal[] }>(`/admin/expert-withdrawals${status ? `?status=${encodeURIComponent(status)}` : ''}`, { headers: adminHeaders() })
  },
  updateAdminExpertWithdrawal(id: string, payload: Record<string, unknown>) {
    return request<BackendExpertWithdrawal>(`/admin/expert-withdrawals/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminAgreement(id = 'expert-cooperation-rules') {
    return request<BackendSiteAgreement>(`/admin/site/agreements/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  saveAdminAgreement(id: string, payload: Partial<BackendSiteAgreement>) {
    return request<BackendSiteAgreement>(`/admin/site/agreements/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  createAdminNews(payload: Partial<BackendNewsArticle>) {
    return request<BackendNewsArticle>('/admin/news', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeNewsArticle)
  },
  updateAdminNews(id: string, payload: Partial<BackendNewsArticle>) {
    return request<BackendNewsArticle>(`/admin/news/${id}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeNewsArticle)
  },
  publishNews(id: string) {
    return request<BackendNewsArticle>(`/admin/news/${id}/publish`, { method: 'POST', headers: adminHeaders() }).then(normalizeNewsArticle)
  },
  offlineNews(id: string) {
    return request<BackendNewsArticle>(`/admin/news/${id}/offline`, { method: 'POST', headers: adminHeaders() }).then(normalizeNewsArticle)
  },
  draftNews(id: string) {
    return request<BackendNewsArticle>(`/admin/news/${id}/draft`, { method: 'POST', headers: adminHeaders() }).then(normalizeNewsArticle)
  },
  deleteNews(id: string) {
    return request<{ ok: boolean }>(`/admin/news/${id}`, { method: 'DELETE', headers: adminHeaders() })
  },
  createAdminProduct(payload: Partial<BackendProduct>) {
    return request<BackendProduct>('/admin/products', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminProduct(id: string, payload: Partial<BackendProduct>) {
    return request<BackendProduct>(`/admin/products/${id}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  publishProduct(id: string) {
    return request<BackendProduct>(`/admin/products/${id}/publish`, { method: 'POST', headers: adminHeaders() })
  },
  offlineProduct(id: string) {
    return request<BackendProduct>(`/admin/products/${id}/offline`, { method: 'POST', headers: adminHeaders() })
  },
  adminCoupons(filters: { status?: string; discountType?: string; search?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    if (filters.discountType) query.set('discountType', filters.discountType)
    if (filters.search) query.set('search', filters.search)
    return request<{ items: BackendCoupon[] }>(`/admin/coupons${query.toString() ? `?${query.toString()}` : ''}`, { headers: adminHeaders() })
  },
  adminCoupon(id: string) {
    return request<BackendCoupon>(`/admin/coupons/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  saveAdminCoupon(couponId: string | null, payload: Partial<BackendCoupon> & Record<string, unknown>) {
    return request<BackendCoupon>(couponId ? `/admin/coupons/${encodeURIComponent(couponId)}` : '/admin/coupons', {
      method: couponId ? 'PATCH' : 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  createAdminCoupon(payload: Partial<BackendCoupon> & Record<string, unknown>) {
    return request<BackendCoupon>('/admin/coupons', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  updateAdminCoupon(id: string, payload: Partial<BackendCoupon> & Record<string, unknown>) {
    return request<BackendCoupon>(`/admin/coupons/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  deleteAdminCoupon(id: string) {
    return request<{ ok: boolean; paused?: boolean; item?: BackendCoupon }>(`/admin/coupons/${encodeURIComponent(id)}`, { method: 'DELETE', headers: adminHeaders() })
  },
  adminCouponRedemptions(id: string) {
    return request<{ items: BackendCouponRedemption[] }>(`/admin/coupons/${encodeURIComponent(id)}/redemptions`, { headers: adminHeaders() })
  },
  previewAdminCoupon(payload: Record<string, unknown>) {
    return request<BackendCheckoutPreview>('/admin/coupons/preview', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminSettlements(filters: { status?: string } = {}) {
    const query = new URLSearchParams()
    if (filters.status) query.set('status', filters.status)
    return request<{ items: BackendSettlement[] }>(`/admin/settlements${query.toString() ? `?${query}` : ''}`, { headers: adminHeaders() })
  },
  staffTasks(params: { status?: string; type?: string; scope?: string } = {}) {
    const search = new URLSearchParams()
    if (params.status) search.set('status', params.status)
    if (params.type) search.set('type', params.type)
    if (params.scope) search.set('scope', params.scope)
    return request<{ items: BackendTask[] }>(`/staff/tasks${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
  },
  updateStaffTask(id: string, status: string, payload: Record<string, unknown> = {}) {
    return request<BackendTask>(`/staff/tasks/${id}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ status, ...payload }),
    })
  },
  staffConsultingRequests(params: { status?: string; scope?: string } = {}) {
    const search = new URLSearchParams()
    if (params.status) search.set('status', params.status)
    if (params.scope) search.set('scope', params.scope)
    return request<{ items: BackendConsultingRequest[] }>(`/staff/consulting-requests${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
  },
  adminConsultingOptions() {
    return request<{ optionSets: BackendConsultingOptionSet[] }>('/admin/consulting-options', { headers: adminHeaders() })
  },
  saveAdminConsultingOptions(optionSets: BackendConsultingOptionSet[]) {
    return request<{ optionSets: BackendConsultingOptionSet[] }>('/admin/consulting-options', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ optionSets }),
    })
  },
  adminDataServiceOptions() {
    return request<{ optionSets: BackendConsultingOptionSet[] }>('/admin/data-service/options', { headers: adminHeaders() })
  },
  saveAdminDataServiceOptions(optionSets: BackendConsultingOptionSet[]) {
    return request<{ optionSets: BackendConsultingOptionSet[] } | { ok: boolean; message?: string }>('/admin/data-service/options', {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ optionSets }),
    })
  },
  adminConsultingRequests(params: { status?: string; scope?: string; keyword?: string; assigneeId?: string; ownerDepartment?: string; page?: number; pageSize?: number } = {}) {
    const search = new URLSearchParams()
    if (params.status) search.set('status', params.status)
    if (params.scope) search.set('scope', params.scope)
    if (params.keyword) search.set('keyword', params.keyword)
    if (params.assigneeId) search.set('assigneeId', params.assigneeId)
    if (params.ownerDepartment) search.set('ownerDepartment', params.ownerDepartment)
    if (params.page) search.set('page', String(params.page))
    if (params.pageSize) search.set('pageSize', String(params.pageSize))
    return request<BackendConsultingRequestList>(`/admin/consulting-requests${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
  },
  adminConsultingRequest(id: string) {
    return request<BackendConsultingRequest>(`/admin/consulting-requests/${encodeURIComponent(id)}`, { headers: adminHeaders() })
  },
  updateAdminConsultingRequest(id: string, payload: Record<string, unknown> = {}) {
    return request<BackendConsultingRequest>(`/admin/consulting-requests/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  cancelAdminConsultingRequest(id: string, payload: Record<string, unknown> = {}) {
    return request<BackendConsultingRequest>(`/admin/consulting-requests/${encodeURIComponent(id)}/cancel`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    })
  },
  adminDataServiceRequests(params: { status?: string; scope?: string; keyword?: string; assigneeId?: string; departmentId?: string; dateFrom?: string; dateTo?: string; page?: number; pageSize?: number } = {}) {
    const search = new URLSearchParams()
    if (params.status) search.set('status', params.status)
    if (params.scope) search.set('scope', params.scope)
    if (params.keyword) search.set('keyword', params.keyword)
    if (params.assigneeId) search.set('assigneeId', params.assigneeId)
    if (params.departmentId) search.set('departmentId', params.departmentId)
    if (params.dateFrom) search.set('dateFrom', params.dateFrom)
    if (params.dateTo) search.set('dateTo', params.dateTo)
    if (params.page) search.set('page', String(params.page))
    if (params.pageSize) search.set('pageSize', String(params.pageSize))
    return request<BackendDataServiceRequestList>(`/admin/data-service/requests${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
      .then((result) => ({ ...result, items: result.items.map(normalizeDataServiceRequest) }))
  },
  adminDataServiceRequest(id: string) {
    return request<BackendDataServiceRequest>(`/admin/data-service/requests/${encodeURIComponent(id)}`, { headers: adminHeaders() }).then(normalizeDataServiceRequest)
  },
  updateAdminDataServiceRequest(id: string, payload: Record<string, unknown> = {}) {
    return request<BackendDataServiceRequest>(`/admin/data-service/requests/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeDataServiceRequest)
  },
  cancelAdminDataServiceRequest(id: string, payload: Record<string, unknown> = {}) {
    return request<BackendDataServiceRequest>(`/admin/data-service/requests/${encodeURIComponent(id)}/cancel`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeDataServiceRequest)
  },
  staffDataServiceRequests(params: { status?: string; scope?: string; keyword?: string } = {}) {
    const search = new URLSearchParams()
    if (params.status) search.set('status', params.status)
    if (params.scope) search.set('scope', params.scope)
    if (params.keyword) search.set('keyword', params.keyword)
    return request<{ items: BackendDataServiceRequest[] }>(`/staff/data-service-requests${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
      .then((result) => ({ items: result.items.map(normalizeDataServiceRequest) }))
  },
  staffDataServiceRequest(id: string) {
    return request<BackendDataServiceRequest>(`/staff/data-service-requests/${encodeURIComponent(id)}`, { headers: adminHeaders() }).then(normalizeDataServiceRequest)
  },
  updateStaffDataServiceRequest(id: string, payload: Record<string, unknown> = {}) {
    return request<BackendDataServiceRequest>(`/staff/data-service-requests/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeDataServiceRequest)
  },
  staffCheckinProjects(params: { kind?: 'event' | 'course' | 'all'; range?: 'today' | 'upcoming' | 'all' } = {}) {
    const search = new URLSearchParams()
    if (params.kind) search.set('kind', params.kind)
    if (params.range) search.set('range', params.range)
    return request<{ items: BackendCheckinProject[] }>(`/staff/checkin/projects${search.toString() ? `?${search}` : ''}`, { headers: adminHeaders() })
  },
  staffCheckinRegistrations(params: { kind: 'event' | 'course'; productId: string; status?: string; keyword?: string; page?: string; pageSize?: string }) {
    const search = new URLSearchParams()
    search.set('kind', params.kind)
    search.set('productId', params.productId)
    if (params.status) search.set('status', params.status)
    if (params.keyword) search.set('keyword', params.keyword)
    if (params.page) search.set('page', params.page)
    if (params.pageSize) search.set('pageSize', params.pageSize)
    return request<BackendCheckinRegistrationList>(`/staff/checkin/registrations?${search}`, { headers: adminHeaders() })
      .then((result) => ({
        ...result,
        items: result.items.map((item) => params.kind === 'event'
          ? normalizeEventRegistration(item as BackendEventRegistration) as BackendCheckinRegistration
          : normalizeCourseRegistration(item as BackendCourseRegistration) as BackendCheckinRegistration),
      }))
  },
  staffCheckinScan(payload: { kind: 'event' | 'course'; productId?: string; checkinCode: string; source?: string; note?: string }) {
    return request<{ registration: BackendCheckinRegistration; alreadyCheckedIn: boolean }>('/staff/checkin/scan', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then((result) => ({
      ...result,
      registration: payload.kind === 'event'
        ? normalizeEventRegistration(result.registration as BackendEventRegistration) as BackendCheckinRegistration
        : normalizeCourseRegistration(result.registration as BackendCourseRegistration) as BackendCheckinRegistration,
    }))
  },
  staffCheckinManual(payload: { kind: 'event' | 'course'; productId?: string; registrationId: string; source?: string; note?: string }) {
    return request<{ registration: BackendCheckinRegistration; alreadyCheckedIn: boolean }>('/staff/checkin/manual', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then((result) => ({
      ...result,
      registration: payload.kind === 'event'
        ? normalizeEventRegistration(result.registration as BackendEventRegistration) as BackendCheckinRegistration
        : normalizeCourseRegistration(result.registration as BackendCourseRegistration) as BackendCheckinRegistration,
    }))
  },
  staffCheckinPassportRegistration(payload: { kind: 'event' | 'course'; productId: string; passportNo?: string; phone?: string; note?: string; checkIn?: boolean; source?: string }) {
    return request<{ registration: BackendCheckinRegistration; alreadyRegistered: boolean; alreadyCheckedIn: boolean }>('/staff/checkin/passport-registration', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then((result) => ({
      ...result,
      registration: payload.kind === 'event'
        ? normalizeEventRegistration(result.registration as BackendEventRegistration) as BackendCheckinRegistration
        : normalizeCourseRegistration(result.registration as BackendCourseRegistration) as BackendCheckinRegistration,
    }))
  },
  staffEvents() {
    return request<{ items: BackendEventProduct[] }>('/staff/events', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventProduct) }))
  },
  staffCourses() {
    return request<{ items: BackendCourseProduct[] }>('/staff/courses', { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeCourseProduct) }))
  },
  staffEventRegistrations(eventId: string, status = '') {
    return request<{ items: BackendEventRegistration[] }>(`/staff/events/${encodeURIComponent(eventId)}/registrations${status ? `?status=${encodeURIComponent(status)}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  createStaffEventRegistration(eventId: string, payload: { passportNo?: string; phone?: string; note?: string; checkIn?: boolean; source?: string }) {
    return request<BackendEventRegistration>(`/staff/events/${encodeURIComponent(eventId)}/registrations`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventRegistration)
  },
  staffCourseRegistrations(courseId: string, status = '') {
    return request<{ items: BackendCourseRegistration[] }>(`/staff/courses/${encodeURIComponent(courseId)}/registrations${status ? `?status=${encodeURIComponent(status)}` : ''}`, { headers: adminHeaders() }).then((result) => ({ items: result.items.map(normalizeCourseRegistration) }))
  },
  createStaffCourseRegistration(courseId: string, payload: { passportNo?: string; phone?: string; note?: string; checkIn?: boolean; source?: string }) {
    return request<BackendCourseRegistration>(`/staff/courses/${encodeURIComponent(courseId)}/registrations`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeCourseRegistration)
  },
  staffEventManualCheckin(id: string, payload: { eventId?: string; source?: string; note?: string } = {}) {
    return request<BackendEventRegistration>(`/staff/event-registrations/${encodeURIComponent(id)}`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventRegistration)
  },
  staffCourseManualCheckin(id: string, payload: { courseId?: string; source?: string; note?: string } = {}) {
    return request<BackendCourseRegistration>(`/staff/course-registrations/${encodeURIComponent(id)}`, {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeCourseRegistration)
  },
  staffEventCheckinScan(payload: { eventId?: string; checkinCode: string; source?: string; note?: string }) {
    return request<BackendEventRegistration>('/staff/event-checkins/scan', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeEventRegistration)
  },
  staffCourseCheckinScan(payload: { courseId?: string; checkinCode: string; source?: string; note?: string }) {
    return request<BackendCourseRegistration>('/staff/course-checkins/scan', {
      method: 'POST',
      headers: adminHeaders(),
      body: JSON.stringify(payload),
    }).then(normalizeCourseRegistration)
  },
  updateStaffConsultingRequest(id: string, status: string, payload: Record<string, unknown> = {}) {
    return request<BackendConsultingRequest>(`/staff/consulting-requests/${id}`, {
      method: 'PATCH',
      headers: adminHeaders(),
      body: JSON.stringify({ status, ...payload }),
    })
  },
}
