import Taro from '@tarojs/taro'
import type { CartItem, ConsultingSite, DeliveryTask, NewsArticle, OrderRecord, ProductType, ServiceProduct, UserProfile } from '@/types'

function normalizeApiBase(value: string) {
  const base = value.replace(/\/+$/, '')
  return /\/api$/i.test(base) ? base : `${base}/api`
}

const apiBases = [normalizeApiBase('https://bigdata.dtacloud.cn/api')]
const assetBase = apiBases[0].replace(/\/api\/?$/, '')
const requestTimeoutMs = 15000
const networkFailurePattern = /fail|timeout|Failed|请求失败：0|request:fail/i
export const defaultPaymentChannel: 'dev' | 'wechat_jsapi' = 'wechat_jsapi'
const adminToken = ''
export const BRAND_NAME = '大连市大数据研究院'
export const BRAND_LOGO_FILE_ID = 'd1b1d1b1-2026-4000-9000-000000000001'
export const BRAND_LOGO_BUCKET_URL = `${assetBase}/api/files/${BRAND_LOGO_FILE_ID}?v=original-logo`
export const BRAND_LOGO_URL = BRAND_LOGO_BUCKET_URL

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

export function fileAssetUrl(id: string) {
  return `${assetBase}/api/files/${id}`
}

export function accountInvoiceFileUrl(invoiceNo: string) {
  return `${apiBases[0]}/account/invoice-applications/${encodeURIComponent(invoiceNo)}/file`
}

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 type PcScanLoginStatus = 'pending' | 'scanned' | 'need_phone' | 'need_profile' | 'confirming' | 'confirmed' | 'expired' | 'cancelled'
export type PcScanNextAction = 'bind_phone' | 'complete_profile' | 'enter_app'
export type PcScanClientInfo = {
  region?: string
  device?: string
  browser?: string
}

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

export interface BackendMembershipSubscription {
  id: string
  tier: 'junior' | 'senior'
  billingCycle: 'monthly' | 'yearly' | 'manual_grant'
  status: 'active' | 'past_due' | 'expired' | 'canceled' | 'refunded' | string
  startsAt: string
  expiresAt: string
  daysLeft: number
  autoRenew: boolean
  cancelRequestedAt?: string | null
  cancelRequestedReason?: string
  customerManager?: {
    assignmentId?: string
    staffAccountId?: string
    staffName?: string
    staffPhone?: string
    note?: string
    assignedAt?: string
  }
  createdAt: string
  updatedAt?: string
}

export interface BackendMembershipBenefit {
  code: string
  label: string
  groupKey?: string
  benefitType?: string
  targetType?: string
  executionMode?: string
  status?: string
  sortOrder?: number
  description?: string
}

export interface BackendMembershipEntitlementAccount {
  id: string
  benefitCode: string
  periodKey: string
  quotaTotal: number
  quotaUsed: number
  quotaRemaining: number
  validFrom?: string
  validTo?: string
  status: string
  metadata?: Record<string, unknown>
}

export interface BackendMembershipServiceAssignment {
  id: string
  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
}

interface BackendProduct {
  id: string
  slug: string
  type: ProductType
  title: string
  summary: string
  priceAmount: number
  status: string
  coverUrl?: string
  fileUrl?: string
}

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
  recommended?: boolean
  sortOrder?: number
}

export interface BackendDataProduct extends BackendProduct {
  productId: string
  productStatus?: string
  category: string
  fileFormat: string
  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 BackendConsultingOption {
  code: string
  label: string
  description?: string
  sortOrder: number
  status: 'active' | 'disabled'
}

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

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 }[]
}

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 type BackendWechatAiSourceType = 'consulting' | 'course' | 'event' | 'data' | 'agent' | 'expert'

export interface BackendWechatAiCard {
  type: 'service' | 'account'
  sourceType: BackendWechatAiSourceType | string
  sourceLabel: string
  id: string
  slug?: string
  title: string
  summary: string
  category?: string
  priceLabel?: string
  statusLabel?: string
  meta?: string
  amountLabel?: string
  timeLabel?: string
  nextStep?: string
  tags?: string[]
  action?: { type: 'navigate'; label: string; url: string }
}

export interface BackendWechatAiLeadDraft {
  type: 'consulting' | 'data_service'
  payload: Record<string, unknown>
  missingFields: string[]
  submitEndpoint: string
  pagePath: string
  draftKey?: string
  actionUrl?: string
}

export interface BackendWechatAiAssistResponse {
  reply: string
  requiresAuth: boolean
  authStatus: 'anonymous' | 'invalid' | 'authenticated'
  cards: BackendWechatAiCard[]
  accountSummary?: {
    domain: string
    label: string
    scopeCode: string
    summary: Record<string, unknown>
  }
  draft: BackendWechatAiLeadDraft | null
  actions: Array<{ type: string; label: string; url?: string; endpoint?: string }>
  permission?: BackendAiPermission
  risk?: { code: string; label: string }
  intent: string
}

export type BackendAiAccessLevel = 'denied' | 'read' | 'operate'

export interface BackendAiPermission {
  scopeCode: string
  groupKey: 'read' | 'operate' | string
  label: string
  description: string
  maxAccessLevel: BackendAiAccessLevel
  defaultAccessLevel: BackendAiAccessLevel
  accessLevel: BackendAiAccessLevel
  sortOrder: number
  updatedAt?: string | null
}

export interface BackendAiPermissionsResponse {
  items: BackendAiPermission[]
  dangerousScopes: string[]
}

export type BackendRecommendationSourceType = 'news' | 'course' | 'event' | 'data' | 'agent' | 'expert'

export type BackendRecommendationSource = BackendNewsArticle | BackendCourseProduct | BackendEventProduct | BackendDataProduct | BackendAgentProduct | BackendExpertProfile

export type BackendRecommendationPlacement = 'home.news' | 'home.courses' | 'home.events' | 'home.experts' | 'news.carousel' | 'courses.carousel' | 'events.carousel'

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
  title?: string
  subtitle?: string
  imageUrl?: string
  href?: string
  ctaLabel?: string
  badge?: string
  startsAt?: string | null
  endsAt?: string | null
  priceAmount?: number
  source?: BackendRecommendationSource | null
}

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

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

export interface BackendOrder {
  id: string
  orderNo: string
  settlementNo?: string
  userId?: string
  userPhone?: string
  status: 'pending_payment' | 'paid' | 'completed' | 'closed'
  items: Array<{
    productId: string
    productType: ProductType
    titleSnapshot: string
    unitPriceAmount: number
    quantity: number
    payableAmount: number
    billingCycle?: 'once' | 'monthly' | 'yearly' | 'manual_grant'
  }>
  subtotalAmount: number
  memberDiscountAmount: number
  couponDiscountAmount: number
  totalAmount: number
  paidAmount: number
  currency?: string
  invoiceStatus?: BackendInvoiceStatus | ''
  invoiceApplication?: BackendInvoiceApplication | null
  createdAt: string
  updatedAt?: string
}

export interface BackendCheckoutPreview {
  items: Array<{
    productId: string
    productType: ProductType
    titleSnapshot: string
    unitPriceAmount: number
    listPriceAmount?: number
    memberDiscountAmount?: number
    quantity: number
    payableAmount: number
    billingCycle?: 'once' | 'monthly' | 'yearly' | 'manual_grant'
    pricingSource?: string
    membershipDiscountNote?: string
  }>
  subtotalAmount: number
  memberDiscountAmount: number
  couponDiscountAmount: number
  paidAmount: number
  totalAmount: number
  currency: string
  membershipChange?: {
    type: 'activate' | 'renew' | 'upgrade'
    upgradeCreditAmount: number
  } | null
}

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

export interface BackendInvoiceApplication {
  id: string
  invoiceNo: string
  invoiceType: string
  invoiceTypeLabel?: string
  orderId: string
  orderNo: string
  settlementNo?: string
  userId: string
  userPhone?: string
  title: string
  taxNumber?: string
  email: string
  amount: number
  status: BackendInvoiceStatus
  provider: string
  providerInvoiceId?: string
  pdfFileId?: string
  fileName?: string
  fileUrl?: string
  failureReason?: string
  remark?: string
  adminNote?: string
  issuedBy?: string
  issuedAt?: string
  fileUploadedAt?: string
  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
  orderId: string
  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
  expiresAt: string
  createdAt: string
  updatedAt: string
}

export interface BackendNotification {
  id: string
  batchId?: string | null
  scene: string
  channel: 'in_app' | 'sms' | 'wechat_subscribe' | 'email' | string
  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 BackendStaffAccount {
  id: string
  displayName: string
  phone: string
  role: string
  permissions: string[]
}

export interface BackendStaffWorkbenchModule {
  key: 'checkin' | 'tasks' | 'consulting' | 'data-service' | 'orders' | string
  title: string
  entry: string
  permissions: string[]
  counts?: Record<string, number>
}

export interface BackendStaffWorkbench {
  account: BackendStaffAccount
  defaultModule: string
  modules: BackendStaffWorkbenchModule[]
}

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

export interface BackendNewsArticle {
  id: string
  slug: string
  title: string
  categoryCode?: string
  category: string
  summary: string
  content: string
  authorName?: string
  coverUrl?: string
  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
}

export type BackendAccessState = 'closed' | 'free' | 'paid'
export type BackendRegistrationStatus =
  | 'pending_payment'
  | 'registered'
  | 'waitlisted'
  | 'cancel_requested'
  | 'cancelled'
  | 'checked_in'
  | 'no_show'
  | 'refunded'

export interface BackendEventProduct extends BackendProduct {
  productId: string
  productStatus?: string
  purchaseFlow?: string
  fulfillmentFlow?: string
  eventType: string
  topic: string
  eventFormat: string
  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
  initialRegisteredCount?: number
  checkedInCount: number
  registrationStatus?: 'open' | 'closed' | string
  registrationStats?: {
    total?: number
    pendingPayment?: number
    registered?: number
    waitlisted?: number
    checkedIn?: number
    cancelled?: number
  }
  memberLevelRequired?: number
  registeredAccess?: BackendAccessState
  juniorAccess?: BackendAccessState
  seniorAccess?: BackendAccessState
  registeredPriceAmount?: number
  juniorPriceAmount?: number
  seniorPriceAmount?: number
  recommended?: boolean
  sortOrder?: number
  status: string
}

export interface BackendCourseProduct extends BackendProduct {
  productId: string
  productStatus?: string
  purchaseFlow?: string
  fulfillmentFlow?: string
  courseType?: 'free' | 'paid' | 'junior' | 'senior' | string
  memberLevelRequired?: number
  accessPolicy?: string
  registeredAccess?: BackendAccessState
  juniorAccess?: BackendAccessState
  seniorAccess?: BackendAccessState
  registeredPriceAmount?: number
  juniorPriceAmount?: number
  seniorPriceAmount?: number
  instructor: string
  lessonCount: number
  startsAt: string | null
  location: string
  courseStatus: 'upcoming' | 'ongoing' | 'completed' | 'anytime'
  direction: string
  courseFormat: string
  coverUrl: string
  liveUrl?: string
  replayUrl?: string
  coverLabel: string
  audience: string
  outcomes: string[]
  modules: string[]
  lessonModules: Array<{
    id: string
    title: string
    description: string
    videoUrl: string
    materialUrl: string
    durationMinutes: number
    sortOrder: number
    status: string
  }>
  accessNote: string
  capacity: number
  registeredCount: number
  checkedInCount: number
  checkinRequired: boolean
  recommended?: boolean
  sortOrder?: number
}

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: BackendRegistrationStatus
  checkinCode: string
  checkedInAt: string | null
  checkinSource?: string | null
  checkinNote?: string | null
  checkedInByStaffId?: string | null
  checkedInByStaffName?: string | null
  createdAt: string
  updatedAt?: string
  event: BackendEventProduct
  alreadyCheckedIn?: boolean
  alreadyRegistered?: boolean
}

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: BackendRegistrationStatus
  checkinCode: string
  checkedInAt: string | null
  checkinSource?: string | null
  checkinNote?: string | null
  checkedInByStaffId?: string | null
  checkedInByStaffName?: string | null
  createdAt: string
  updatedAt?: string
  course: BackendCourseProduct
  alreadyCheckedIn?: boolean
  alreadyRegistered?: boolean
}

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 BackendConsultingRequest {
  id: string
  requestNo: string
  userId: string
  userPhone?: 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 | null
  assigneeName?: string | null
  progressNote: string
  solutionSummary: string
  chargeRequired?: boolean
  quotedTitle?: string
  quotedAmount?: number
  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
  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
  resultSummary: string
  internalNote?: string
  completedAt?: string | null
  createdAt: string
  updatedAt: string
}

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

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

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

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?: BackendFileRef[]
  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
  meetingUpdatedAt?: string | null
  pendingChange?: {
    id: string
    requesterType: 'user' | 'expert' | 'admin'
    changeType?: 'reschedule' | 'cancel'
    requestedStartsAt: string
    requestedEndsAt: string
    reason: string
    status: string
    userConfirmedAt?: string | null
    expertConfirmedAt?: string | null
    adminNote?: string
    createdAt?: string
  } | null
  completedAt?: string | null
  expert: BackendExpertProfile
  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?: BackendExpertProfile
  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 function yuan(cents: number) {
  return Math.round(cents / 100)
}

function formatMiniDateTime(value?: string | null) {
  if (!value) return ''
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return ''
  return `${date.getMonth() + 1}月${date.getDate()}日 ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
}

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

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

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

function queryString(params: Record<string, string | undefined>) {
  const query = Object.entries(params)
    .filter(([, value]) => value)
    .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value || '')}`)
    .join('&')
  return query ? `?${query}` : ''
}

type RequestOptions = {
  method?: 'GET' | 'POST' | 'PATCH'
  data?: unknown
  header?: Record<string, string>
}

function connectionError(action: string, error: unknown) {
  const detail = error instanceof Error && error.message ? `：${error.message}` : ''
  return new Error(`${action}失败，请检查网络或小程序合法域名配置${detail}`)
}

async function request<T>(url: string, options: RequestOptions = {}) {
  let lastError: unknown = null
  for (const apiBase of apiBases) {
    try {
      const response = await Taro.request({
        url: `${apiBase}${url}`,
        method: options.method || 'GET',
        data: options.data,
        timeout: requestTimeoutMs,
        header: {
          'content-type': 'application/json',
          ...(options.header || {})
        }
      })
      if (response.statusCode < 200 || response.statusCode >= 300) {
        const data = response.data as { message?: string; error?: string; retryAfter?: number }
        const error = new Error(data?.message || data?.error || `请求失败：${response.statusCode}`) as Error & { statusCode?: number; retryAfter?: number; code?: string }
        error.statusCode = response.statusCode
        if (data?.error) error.code = data.error
        if (Number.isFinite(Number(data?.retryAfter || 0)) && Number(data?.retryAfter || 0) > 0) {
          error.retryAfter = Math.ceil(Number(data?.retryAfter))
        }
        throw error
      }
      return response.data as T
    } catch (error) {
      lastError = error
      if (error instanceof Error && !networkFailurePattern.test(error.message)) throw error
    }
  }
  throw connectionError('后端连接', lastError)
}

async function upload<T>(url: string, token: string, filePath: string, formData: Record<string, string> = {}) {
  let lastError: unknown = null
  for (const apiBase of apiBases) {
    try {
      const response = await Taro.uploadFile({
        url: `${apiBase}${url}`,
        filePath,
        name: 'file',
        formData,
        timeout: requestTimeoutMs,
        header: bearer(token)
      })
      const payload = response.data ? JSON.parse(response.data) : null
      if (response.statusCode < 200 || response.statusCode >= 300) {
        throw new Error(payload?.message || payload?.error || `上传失败：${response.statusCode}`)
      }
      return payload as T
    } catch (error) {
      lastError = error
      if (error instanceof Error && !networkFailurePattern.test(error.message)) throw error
    }
  }
  throw connectionError('上传', lastError)
}

async function uploadRaw<T>(url: string, token: string, filePath: string, fileName: string, mimeType = 'application/octet-stream') {
  const fileData = Taro.getFileSystemManager().readFileSync(filePath) as unknown
  return request<T>(url, {
    method: 'POST',
    data: fileData,
    header: {
      ...bearer(token),
      'x-file-name': encodeURIComponent(fileName || 'upload'),
      'content-type': mimeType
    }
  })
}

export function mapUser(user: BackendUser): UserProfile {
  return {
    id: user.id,
    name: user.displayName || user.phone || '研究院用户',
    phone: user.phone,
    passportNo: user.passportNo,
    wechatId: user.wechatId,
    wechatBound: Boolean(user.wechatId),
    contactPhone: user.contactPhone,
    authProvider: 'wechat',
    onboardingCompleted: user.onboardingCompleted,
    email: user.email,
    organization: user.organization,
    title: user.title,
    city: user.city,
    address: user.address,
    industry: user.industry,
    invoiceTitle: user.invoiceTitle,
    taxNumber: user.taxNumber,
    invoiceEmail: user.invoiceEmail,
    expertApplicationStatus: user.expertApplicationStatus,
    expertProfileStatus: user.expertProfileStatus,
    membershipLevel: memberLevel(user.membershipLevel)
  }
}

export function mapProduct(item: BackendProduct): ServiceProduct {
  return {
    id: item.id,
    type: item.type,
    title: item.title,
    subtitle: `${item.type} · ${item.status === 'published' ? '在售' : item.status}`,
    summary: item.summary,
    price: yuan(item.priceAmount),
    cover: assetUrl(item.coverUrl) || item.type,
    status: item.status === 'published' ? '在售' : item.status,
    category: item.type,
    tags: []
  }
}

export function mapAgentProduct(item: BackendAgentProduct): ServiceProduct {
  return {
    id: item.id,
    type: 'agent',
    title: item.title,
    subtitle: '智能体 · 需提交资料',
    summary: item.summary || item.detailDescription || '',
    price: yuan(item.priceAmount || item.registeredPriceAmount || 0),
    cover: assetUrl(item.coverUrl) || 'agent',
    status: item.status === 'published' ? '在售' : item.status,
    category: '智能体',
    tags: item.scenarioTags || []
  }
}

export function mapDataProduct(item: BackendDataProduct): ServiceProduct {
  return {
    id: item.id,
    type: 'data',
    title: item.title,
    subtitle: `${item.category || '数据服务'} · ${item.fileFormat || '文件'}`,
    summary: item.summary,
    price: yuan(item.priceAmount || 0),
    cover: assetUrl(item.coverUrl) || 'data',
    status: '提交需求',
    category: item.category || '数据服务',
    tags: [...(item.tags || []), item.fileFormat || '文件'].map((tag) => String(tag || '').trim()).filter(Boolean)
  }
}

export function mapEventProduct(item: BackendEventProduct): ServiceProduct {
  const access = item.registeredAccess || (item.memberLevelRequired && item.memberLevelRequired > 0 ? 'closed' : item.priceAmount === 0 ? 'free' : 'paid')
  const priceAmount = access === 'free' || access === 'closed' ? 0 : item.registeredPriceAmount ?? item.priceAmount ?? 0
  return {
    id: item.id,
    type: 'event',
    title: item.title,
    subtitle: `${item.eventFormat || '活动'}${item.startsAt ? ` · ${formatMiniDateTime(item.startsAt)}` : ''}`,
    summary: item.summary,
    price: yuan(priceAmount),
    cover: assetUrl(item.coverUrl) || 'event',
    status: item.registrationStatus === 'closed' || item.status === 'registration_closed' ? '报名已关闭' : access === 'closed' ? '会员专享' : item.status === 'published' ? '可报名' : item.status,
    location: item.location,
    startsAt: formatMiniDateTime(item.startsAt),
    category: item.topic || '活动',
    mode: item.isOnline ? 'online' : 'offline',
    tags: [item.topic, item.eventFormat].filter(Boolean)
  }
}

export function mapExpertProduct(item: BackendExpertProfile): ServiceProduct {
  const directions = item.directions || item.specialties || []
  return {
    id: `expert-${item.slug || item.id}`,
    type: 'expert',
    title: `${item.name}专家`,
    subtitle: `${item.title || '专家咨询'} · ${item.organization || '大连市大数据研究院'}`,
    summary: item.homepageIntro || item.bio || directions.join('、') || '可预约专家咨询服务。',
    price: yuan(item.priceAmount || 0),
    cover: assetUrl(item.photoUrl) || 'expert',
    status: item.availabilityStatus === 'this-week' ? '本周可约' : item.availabilityStatus === 'next-week' ? '下周可约' : '预约咨询',
    category: '专家预约',
    tags: directions,
  }
}

export function mapCourseProduct(item: BackendCourseProduct): ServiceProduct {
  const access = item.registeredAccess || (item.memberLevelRequired && item.memberLevelRequired > 0 ? 'closed' : item.priceAmount === 0 ? 'free' : 'paid')
  const priceAmount = access === 'free' || access === 'closed' ? 0 : item.registeredPriceAmount ?? item.priceAmount ?? 0
  return {
    id: item.id,
    type: 'course',
    title: item.title,
    subtitle: `${item.courseFormat || '课程'} · ${item.lessonCount || 0}课时`,
    summary: item.summary,
    price: yuan(priceAmount),
    cover: assetUrl(item.coverUrl) || 'course',
    status: item.courseStatus,
    location: item.location,
    startsAt: formatMiniDateTime(item.startsAt),
    duration: `${item.lessonCount || 0}课时`,
    category: item.direction || '课程',
    mode: item.courseFormat === '线下培训' ? 'offline' : 'online',
    tags: [item.direction, item.courseFormat].filter(Boolean)
  }
}

export function mapNewsArticle(item: BackendNewsArticle): NewsArticle {
  const publishedAt = item.publishedAt ? new Date(item.publishedAt) : new Date()
  return {
    id: item.slug || item.id,
    slug: item.slug,
    title: item.title,
    categoryCode: item.categoryCode,
    category: item.category,
    summary: item.summary,
    date: `${publishedAt.getFullYear()}.${String(publishedAt.getMonth() + 1).padStart(2, '0')}.${String(publishedAt.getDate()).padStart(2, '0')}`,
    content: (item.content || item.summary).replace(/src=(["'])\/api\//g, `src=$1${assetBase}/api/`),
    coverUrl: assetUrl(item.coverUrl),
    authorName: item.authorName,
    publishedAt: item.publishedAt,
    relatedArticleIds: item.relatedArticleIds || []
  }
}

export function mapOrder(order: BackendOrder): OrderRecord[] {
  return order.items.map((item) => ({
    id: item.productId,
    type: item.productType,
    title: item.titleSnapshot,
    subtitle: `${item.productType} · 数量 ${item.quantity}`,
    cover: item.productType,
    orderNo: order.orderNo,
    settlementNo: order.settlementNo || order.orderNo.replace(/^ORD/, 'CKO'),
    amount: yuan(item.unitPriceAmount * item.quantity),
    price: yuan(item.unitPriceAmount),
    paidAmount: yuan(order.totalAmount),
    purchasedAt: new Date(order.createdAt).toLocaleString('zh-CN'),
    productStatus: order.status === 'paid' || order.status === 'completed' ? statusFor(item.productType) : '待支付',
    invoiceStatus: order.invoiceStatus || '',
    invoiceApplication: order.invoiceApplication || null
  }))
}

export function mapTask(task: BackendTask): DeliveryTask {
  const steps = task.type === 'agent'
    ? ['提交资料', '需求审核', '智能体配置', '交付验收']
    : ['提交背景', '服务确认', '执行交付', '完成归档']
  const currentStep = task.status === 'pending_material' ? 0 : task.status === 'assigned' ? 1 : task.status === 'in_progress' || task.status === 'pending_confirm' ? 2 : 3
  return {
    id: task.taskNo || task.id,
    orderNo: task.orderNo || task.orderId,
    productId: task.productId,
    title: task.productTitle || task.title,
    type: task.type,
    status: task.status,
    statusText: taskStatusText(task.status),
    currentStep,
    steps,
    progressNote: task.progressNote,
    resultSummary: task.resultSummary,
    updatedAt: task.updatedAt
  }
}

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

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

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

function normalizeConsultingRequest<T extends BackendConsultingRequest>(item: T): T {
  return { ...item, finalFileUrl: assetUrl(item.finalFileUrl) }
}

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

function normalizeCourseProduct<T extends 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 normalizeNewsArticle<T extends BackendNewsArticle>(item: T): T {
  return {
    ...item,
    coverUrl: assetUrl(item.coverUrl),
    content: typeof item.content === 'string'
      ? item.content.replace(/src=(["'])\/api\//g, `src=$1${assetBase}/api/`)
      : item.content
  }
}

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

function normalizeRecommendationSlot<T extends BackendRecommendationSlot>(slot: T): T {
  return {
    ...slot,
    imageUrl: assetUrl(slot.imageUrl),
    imageUrlOverride: assetUrl(slot.imageUrlOverride),
    source: normalizeRecommendationSource(slot.sourceType, slot.source) as T['source']
  }
}

function normalizeRecommendationResponse<T extends BackendRecommendationResponse>(response: T): T {
  const placements = response.placements || {}
  const nextPlacements = Object.fromEntries(
    Object.entries(placements).map(([key, slots]) => [key, (slots || []).map(normalizeRecommendationSlot)])
  ) as T['placements']
  return {
    ...response,
    placements: nextPlacements,
    items: (response.items || []).map(normalizeRecommendationSlot)
  }
}

function normalizeSiteHome<T extends BackendSiteHome>(home: T): T {
  return {
    ...home,
    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) }))
  }
}

function normalizeEventRegistration<T extends BackendEventRegistration>(item: T): T {
  return { ...item, event: normalizeEventProduct(item.event) }
}

function normalizeCourseRegistration<T extends BackendCourseRegistration>(item: T): T {
  return { ...item, course: normalizeCourseProduct(item.course) }
}

function normalizeFileRef<T extends BackendFileRef>(item: T): T {
  return {
    ...item,
    url: assetUrl(item.url || `/api/files/${item.id}`)
  }
}

function normalizeExpertProfile<T extends BackendExpertProfile>(item: T): T {
  return {
    ...item,
    photoUrl: assetUrl(item.photoUrl)
  }
}

function normalizeExpertApplication<T extends BackendExpertApplication>(item: T): T {
  return {
    ...item,
    photoUrl: assetUrl(item.photoUrl),
    attachments: (item.attachments || []).map(normalizeFileRef)
  }
}

function normalizeExpertApplicationOrNull(item: BackendExpertApplication | null): BackendExpertApplication | null {
  return item ? normalizeExpertApplication(item) : item
}

function normalizeExpertBooking<T extends BackendExpertBooking>(item: T): T {
  return {
    ...item,
    meetingUrl: assetUrl(item.meetingUrl),
    materialFiles: (item.materialFiles || []).map(normalizeFileRef),
    expert: item.expert ? normalizeExpertProfile(item.expert) : item.expert
  }
}

function normalizeExpertWithdrawal<T extends BackendExpertWithdrawal>(item: T): T {
  return {
    ...item,
    expert: item.expert ? normalizeExpertProfile(item.expert) : item.expert
  }
}

export function backendProductId(item: Pick<CartItem, 'id' | 'type' | 'expertBookingId' | 'dataServiceRequestId'>) {
  if (item.dataServiceRequestId || item.id === 'data-service-custom') return 'data-service-custom'
  if (item.type === 'consulting' || item.id === 'consulting-service-custom') return 'consulting-service-custom'
  if (item.id.startsWith('membership-')) return item.id
  if (item.type === 'event' && item.id.startsWith('event-')) return item.id
  if (item.type === 'course' && item.id.startsWith('course-')) return item.id
  if (item.type === 'data' && item.id.startsWith('data-')) return item.id
  if (item.type === 'agent' && item.id.startsWith('agent-')) return item.id
  if (['expert-city-consulting', 'course-city-method', 'event-bigdata-summit', 'data-index-2025', 'agent-policy-brief'].includes(item.id)) return item.id
  if (item.type === 'expert') return 'expert-city-consulting'
  if (item.type === 'course') return 'course-city-method'
  if (item.type === 'event') return 'event-bigdata-summit'
  if (item.type === 'data') return 'data-index-2025'
  if (item.type === 'agent') return 'agent-policy-brief'
  if (item.type === 'membership') return item.id.includes('senior') ? 'membership-senior' : 'membership-junior'
  return item.id
}

function statusFor(type: ProductType) {
  if (type === 'expert') return '待同意'
  if (type === 'event') return '已报名'
  if (type === 'course') return '已报名'
  if (type === 'agent') return '待提交资料'
  if (type === 'membership') return '已开通'
  if (type === 'data') return '已付款'
  return '-'
}

function taskStatusText(status: string) {
  if (status === 'completed') return '已完成'
  if (status === 'pending_confirm') return '待确认'
  if (status === 'in_progress') return '配置中'
  if (status === 'assigned') return '资料审核中'
  if (status === 'cancelled') return '已取消'
  return '待提交资料'
}

export const backend = {
  miniappWechatLogin(jsCode: string, pcSessionId = '') {
    return request<{ token: string; user: BackendUser | null; miniappSessionToken: string; nextAction: 'bind_phone' | 'complete_profile' | 'enter_app'; pcSessionId?: string }>('/auth/miniapp/wechat-login', {
      method: 'POST',
      data: { jsCode, pcSessionId }
    })
  },
  bindMiniappPhone(miniappSessionToken: string, phone: string, code: string) {
    return request<{ token: string; user: BackendUser; nextAction: 'complete_profile' | 'enter_app'; pcSessionId?: string }>('/auth/miniapp/bind-phone', {
      method: 'POST',
      data: { miniappSessionToken, phone, code }
    })
  },
  pcScanLoginStatus(sessionId: string) {
    return request<{ sessionId: string; status: PcScanLoginStatus; redirect: string; exchangeCode?: string | null; expiresAt: string; client?: PcScanClientInfo | null }>(`/auth/pc-scan/status${queryString({ sessionId })}`)
  },
  markPcScanLoginScanned(sessionId: string) {
    return request<{ ok: boolean; status: PcScanLoginStatus }>('/auth/pc-scan/scanned', {
      method: 'POST',
      data: { sessionId }
    })
  },
  preparePcScanLogin(token: string, sessionId: string) {
    return request<{ ok: boolean; status: PcScanLoginStatus; nextAction: PcScanNextAction; client?: PcScanClientInfo | null }>('/auth/pc-scan/prepare', {
      method: 'POST',
      header: bearer(token),
      data: { sessionId }
    })
  },
  confirmPcScanLogin(token: string, sessionId: string) {
    return request<{ ok: boolean }>('/auth/pc-scan/confirm', {
      method: 'POST',
      header: bearer(token),
      data: { sessionId }
    })
  },
  cancelPcScanLogin(token: string, sessionId: string) {
    return request<{ ok: boolean; status: PcScanLoginStatus }>('/auth/pc-scan/cancel', {
      method: 'POST',
      header: bearer(token),
      data: { sessionId }
    })
  },
  sendPhoneCode(phone: string) {
    return request<{ phone?: string; expiresIn?: number }>('/auth/phone/send-code', { method: 'POST', data: { phone } })
  },
  loginByPhone(phone: string, code: string) {
    return request<{ token: string; user: BackendUser }>('/auth/phone/login', { method: 'POST', data: { phone, code } })
  },
  wechatAiAssist(payload: Record<string, unknown>, token = '') {
    return request<BackendWechatAiAssistResponse>('/ai/wechat/assist', {
      method: 'POST',
      data: payload,
      header: token ? bearer(token) : {}
    })
  },
  me(token: string) {
    return request<BackendUser>('/account/me', { header: bearer(token) })
  },
  accountMembership(token: string) {
    return request<BackendAccountMembership>('/account/membership', { header: bearer(token) })
  },
  accountAiPermissions(token: string) {
    return request<BackendAiPermissionsResponse>('/account/ai-permissions', { header: bearer(token) })
  },
  updateAccountAiPermissions(token: string, items: Array<{ scopeCode: string; accessLevel: BackendAiAccessLevel }>) {
    return request<BackendAiPermissionsResponse>('/account/ai-permissions', {
      method: 'PATCH',
      header: bearer(token),
      data: { items }
    })
  },
  cancelAccountMembership(token: string, subscriptionId: string, payload: { reason?: string } = {}) {
    return request<BackendMembershipSubscription>(`/account/membership/subscriptions/${encodeURIComponent(subscriptionId)}/cancel`, {
      method: 'POST',
      header: bearer(token),
      data: 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}` : ''}`, { header: bearer(token) })
  },
  accountNotificationUnreadCount(token: string) {
    return request<{ unreadCount: number }>('/account/notifications/unread-count', { header: bearer(token) })
  },
  markAccountNotificationRead(token: string, id: string) {
    return request<{ id: string; readAt: string }>(`/account/notifications/${encodeURIComponent(id)}/read`, { method: 'POST', header: bearer(token) })
  },
  markAllAccountNotificationsRead(token: string, payload: { category?: string } = {}) {
    return request<{ readCount: number }>('/account/notifications/read-all', { method: 'POST', header: bearer(token), data: payload })
  },
  accountNotificationPreferences(token: string) {
    return request<BackendNotificationPreferences>('/account/notification-preferences', { header: bearer(token) })
  },
  updateAccountNotificationPreferences(token: string, payload: Partial<BackendNotificationPreferences>) {
    return request<BackendNotificationPreferences>('/account/notification-preferences', { method: 'PATCH', header: bearer(token), data: payload })
  },
  updateProfile(token: string, payload: Record<string, unknown>) {
    return request<BackendUser>('/account/profile', { method: 'PATCH', data: payload, header: bearer(token) })
  },
  bindWechat(token: string, wechatId: string) {
    return request<BackendUser>('/account/wechat', { method: 'PATCH', data: { wechatId }, header: bearer(token) })
  },
  closeAccount(token: string, payload: { reason?: string } = {}) {
    return request<{ ok: boolean; closedAt: string; user: BackendUser }>('/account/close', {
      method: 'POST',
      data: payload,
      header: bearer(token)
    })
  },
  staffLoginByPhone(phone: string, code: string) {
    return request<{ token: string; account: BackendStaffAccount }>('/staff-auth/phone-login', { method: 'POST', data: { phone, code } })
  },
  staffMe(token: string) {
    return request<BackendStaffAccount>('/staff-auth/me', { header: bearer(token) })
  },
  staffWorkbench(token: string) {
    return request<BackendStaffWorkbench>('/staff/workbench', { header: bearer(token) })
  },
  completeOnboarding(token: string, payload: Record<string, unknown>) {
    return request<BackendUser>('/account/onboarding', { method: 'POST', data: payload, header: bearer(token) })
  },
  membershipCatalog() {
    return request<BackendMembershipCatalog>('/membership/catalog')
  },
  siteHome() {
    return request<BackendSiteHome>('/site/home').then(normalizeSiteHome)
  },
  products(type = '') {
    return request<{ items: BackendProduct[] }>(`/products${type ? `?type=${type}` : ''}`)
  },
  news(category = '') {
    return request<{ items: BackendNewsArticle[] }>(`/news${category ? `?category=${encodeURIComponent(category)}` : ''}`)
      .then((result) => ({ items: result.items.map(normalizeNewsArticle) }))
  },
  newsCategories() {
    return request<{ items: BackendNewsCategory[] }>('/news-categories')
  },
  newsDetail(slug: string) {
    return request<BackendNewsArticle>(`/news/${encodeURIComponent(slug)}`).then(normalizeNewsArticle)
  },
  siteRecommendations(placements: BackendRecommendationPlacement[] = []) {
    const query = placements.length ? `?placements=${encodeURIComponent(placements.join(','))}` : ''
    return request<BackendRecommendationResponse>(`/site/recommendations${query}`).then(normalizeRecommendationResponse)
  },
  siteConsulting() {
    return request<ConsultingSite>('/site/consulting').then((site) => ({
      ...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 || []
	    }))
	  },
  courseCatalog() {
    return request<{ items: BackendCourseProduct[] }>('/courses/catalog')
      .then((result) => ({ items: result.items.map(normalizeCourseProduct) }))
  },
  courseProduct(slug: string) {
    return request<BackendCourseProduct>(`/courses/catalog/${encodeURIComponent(slug)}`).then(normalizeCourseProduct)
  },
  eventCatalog() {
    return request<{ items: BackendEventProduct[] }>('/events/catalog')
      .then((result) => ({ items: result.items.map(normalizeEventProduct) }))
  },
  eventProduct(slug: string) {
    return request<BackendEventProduct>(`/events/catalog/${encodeURIComponent(slug)}`).then(normalizeEventProduct)
  },
  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')
  },
  agentCatalog() {
    return request<{ items: BackendAgentProduct[] }>('/agents/catalog')
      .then((result) => ({ items: result.items.map(normalizeAgentProduct) }))
  },
  agentProduct(slug: string) {
    return request<BackendAgentProduct>(`/agents/catalog/${encodeURIComponent(slug)}`).then(normalizeAgentProduct)
  },
	  experts(filters: { direction?: string; search?: string; available?: boolean } = {}) {
	    const query = queryString({
	      direction: filters.direction,
	      search: filters.search,
	      available: filters.available ? '1' : undefined
	    })
	    return request<{ items: BackendExpertProfile[] }>(`/experts${query}`)
	      .then((result) => ({ items: result.items.map(normalizeExpertProfile) }))
	  },
	  expertDirections() {
	    return request<{ items: BackendExpertDirection[] }>('/expert-directions')
	  },
	  expertDetail(slug: string) {
	    return request<BackendExpertProfile>(`/experts/${encodeURIComponent(slug)}`)
	      .then(normalizeExpertProfile)
	  },
	  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', { header: bearer(token) })
	      .then(normalizeExpertApplicationOrNull)
	  },
	  submitExpertApplication(token: string, payload: Record<string, unknown>) {
	    return request<BackendExpertApplication>('/account/expert-application', { method: 'POST', data: payload, header: bearer(token) })
	      .then(normalizeExpertApplication)
	  },
	  accountExpertProfile(token: string) {
	    return request<BackendExpertProfile | null>('/account/expert-profile', { header: bearer(token) })
	      .then((item) => item ? normalizeExpertProfile(item) : item)
	  },
	  setAccountExpertAccepting(token: string, accepting: boolean) {
	    return request<BackendExpertProfile>('/account/expert-profile/accepting', { method: 'PATCH', data: { accepting }, header: bearer(token) })
	      .then(normalizeExpertProfile)
	  },
	  createExpertBooking(token: string, payload: Record<string, unknown>) {
	    return request<BackendExpertBooking>('/account/expert-bookings', { method: 'POST', data: payload, header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
  accountCourseRegistrations(token: string) {
    return request<{ items: BackendCourseRegistration[] }>('/account/course-registrations', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeCourseRegistration) }))
  },
  accountCourseRegistration(token: string, id: string) {
    return request<BackendCourseRegistration>(`/account/course-registrations/${encodeURIComponent(id)}`, { header: bearer(token) }).then(normalizeCourseRegistration)
  },
  accountDataProducts(token: string) {
    return request<{ items: BackendDataProduct[] }>('/account/data-products', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeDataProduct) }))
  },
  createDataServiceRequest(token: string, payload: Record<string, unknown>) {
    return request<BackendDataServiceRequest>('/data-service-requests', { method: 'POST', data: payload, header: bearer(token) })
      .then(normalizeDataServiceRequest)
  },
  accountDataServiceRequests(token: string) {
    return request<{ items: BackendDataServiceRequest[] }>('/account/data-service-requests', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeDataServiceRequest) }))
  },
  accountDataServiceRequest(token: string, id: string) {
    return request<BackendDataServiceRequest>(`/account/data-service-requests/${encodeURIComponent(id)}`, { header: bearer(token) })
      .then(normalizeDataServiceRequest)
  },
  createDataServiceCheckout(token: string, id: string, invoiceRequest?: BackendInvoiceRequest) {
    return request<BackendOrder>(`/account/data-service-requests/${encodeURIComponent(id)}/checkout`, {
      method: 'POST',
      header: bearer(token),
      data: { invoiceRequest }
    })
  },
  createConsultingCheckout(token: string, id: string, invoiceRequest?: BackendInvoiceRequest) {
    return request<BackendOrder>(`/account/consulting-requests/${encodeURIComponent(id)}/checkout`, {
      method: 'POST',
      header: bearer(token),
      data: { invoiceRequest }
    })
  },
  accountEventRegistrations(token: string) {
    return request<{ items: BackendEventRegistration[] }>('/account/event-registrations', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  accountEventRegistration(token: string, id: string) {
    return request<BackendEventRegistration>(`/account/event-registrations/${encodeURIComponent(id)}`, { header: bearer(token) }).then(normalizeEventRegistration)
  },
  accountConsultingRequests(token: string) {
    return request<{ items: BackendConsultingRequest[] }>('/account/consulting-requests', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeConsultingRequest) }))
  },
	  accountExpertBookings(token: string) {
	    return request<{ items: BackendExpertBooking[] }>('/account/expert-bookings', { header: bearer(token) })
	      .then((result) => ({ items: result.items.map(normalizeExpertBooking) }))
	  },
	  accountExpertBooking(token: string, id: string) {
	    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}`, { header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
	  updateAccountExpertBooking(token: string, id: string, payload: Record<string, unknown>) {
	    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}`, { method: 'PATCH', data: payload, header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
	  confirmAccountExpertBookingCompletion(token: string, id: string) {
	    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/confirm-completion`, { method: 'POST', header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
	  disputeAccountExpertBookingCompletion(token: string, id: string, reason: string) {
	    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/dispute`, { method: 'POST', data: { reason }, header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
	  createExpertBookingReschedule(token: string, id: string, payload: Record<string, unknown>) {
	    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/reschedules`, { method: 'POST', data: payload, header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
	  respondExpertBookingReschedule(token: string, id: string, changeId: string, payload: Record<string, unknown>) {
	    return request<BackendExpertBooking>(`/account/expert-bookings/${encodeURIComponent(id)}/reschedules/${encodeURIComponent(changeId)}`, { method: 'PATCH', data: payload, header: bearer(token) })
	      .then(normalizeExpertBooking)
	  },
	  accountExpertSlots(token: string, filters: { from?: string; to?: string } = {}) {
	    const query = queryString({ from: filters.from, to: filters.to })
	    return request<{ items: BackendExpertSlot[] }>(`/account/expert-slots${query}`, { header: bearer(token) })
	  },
	  saveAccountExpertSlot(token: string, payload: Partial<BackendExpertSlot>) {
	    return request<BackendExpertSlot>('/account/expert-slots', { method: 'POST', data: payload, header: bearer(token) })
	  },
	  accountExpertWallet(token: string) {
	    return request<BackendExpertWallet>('/account/expert-wallet', { header: bearer(token) })
	  },
	  accountExpertWithdrawals(token: string) {
	    return request<{ items: BackendExpertWithdrawal[] }>('/account/expert-withdrawals', { header: bearer(token) })
	      .then((result) => ({ items: result.items.map(normalizeExpertWithdrawal) }))
	  },
	  createExpertWithdrawal(token: string, payload: Record<string, unknown>) {
	    return request<BackendExpertWithdrawal>('/account/expert-withdrawals', { method: 'POST', data: payload, header: bearer(token) })
	      .then(normalizeExpertWithdrawal)
	  },
	  uploadAccountFile(token: string, filePath: string, fileName = 'upload', mimeType = 'application/octet-stream') {
	    return uploadRaw<BackendFileRef>('/account/uploads/raw', token, filePath, fileName, mimeType).then(normalizeFileRef)
	  },
  createConsultingRequest(token: string, payload: Record<string, unknown>) {
	    return request<BackendConsultingRequest>('/consulting-requests', { method: 'POST', data: payload, header: bearer(token) })
	      .then(normalizeConsultingRequest)
	  },
  staffCheckinProjects(token: string, params: { kind?: 'event' | 'course' | 'all'; range?: 'today' | 'upcoming' | 'all' } = {}) {
    return request<{ items: BackendCheckinProject[] }>(`/staff/checkin/projects${queryString({
      kind: params.kind,
      range: params.range,
    })}`, { header: bearer(token) })
  },
  staffCheckinRegistrations(token: string, params: { kind: 'event' | 'course'; productId: string; status?: string; keyword?: string; page?: string; pageSize?: string }) {
    return request<BackendCheckinRegistrationList>(`/staff/checkin/registrations${queryString({
      kind: params.kind,
      productId: params.productId,
      status: params.status,
      keyword: params.keyword,
      page: params.page,
      pageSize: params.pageSize,
    })}`, { header: bearer(token) })
  },
  staffCheckinScanUnified(token: string, payload: { kind: 'event' | 'course'; productId?: string; checkinCode: string; source?: string; note?: string }) {
    return request<{ registration: BackendCheckinRegistration; alreadyCheckedIn: boolean }>('/staff/checkin/scan', { method: 'POST', header: bearer(token), data: payload })
  },
  staffCheckinManualUnified(token: string, payload: { kind: 'event' | 'course'; productId?: string; registrationId: string; source?: string; note?: string }) {
    return request<{ registration: BackendCheckinRegistration; alreadyCheckedIn: boolean }>('/staff/checkin/manual', { method: 'POST', header: bearer(token), data: payload })
  },
  staffCheckinPassportRegistration(token: string, payload: { kind: 'event' | 'course'; productId: string; passportNo?: string; phone?: string; checkIn?: boolean; source?: string; note?: string }) {
    return request<{ registration: BackendCheckinRegistration; alreadyRegistered: boolean; alreadyCheckedIn: boolean }>('/staff/checkin/passport-registration', { method: 'POST', header: bearer(token), data: payload })
  },
  staffEvents(token: string) {
    return request<{ items: BackendEventProduct[] }>('/staff/events', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeEventProduct) }))
  },
  staffEventRegistrations(token: string, eventId: string, status = '') {
    return request<{ items: BackendEventRegistration[] }>(`/staff/events/${encodeURIComponent(eventId)}/registrations${status ? `?status=${encodeURIComponent(status)}` : ''}`, { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeEventRegistration) }))
  },
  createStaffEventRegistration(token: string, eventId: string, payload: { passportNo?: string; phone?: string; note?: string; checkIn?: boolean; source?: string }) {
    return request<BackendEventRegistration>(`/staff/events/${encodeURIComponent(eventId)}/registrations`, { method: 'POST', header: bearer(token), data: payload })
      .then(normalizeEventRegistration)
  },
  staffEventRegistration(token: string, id: string) {
    return request<BackendEventRegistration>(`/staff/event-registrations/${encodeURIComponent(id)}`, { header: bearer(token) })
      .then(normalizeEventRegistration)
  },
  staffEventManualCheckin(token: string, id: string, payload: { eventId?: string; source?: string; note?: string }) {
    return request<BackendEventRegistration>(`/staff/event-registrations/${encodeURIComponent(id)}`, { method: 'POST', header: bearer(token), data: payload })
      .then(normalizeEventRegistration)
  },
  staffCheckinScan(token: string, payload: { eventId?: string; checkinCode: string; source?: string; note?: string }) {
    return request<BackendEventRegistration>('/staff/event-checkins/scan', { method: 'POST', header: bearer(token), data: payload })
      .then(normalizeEventRegistration)
  },
  staffCourses(token: string) {
    return request<{ items: BackendCourseProduct[] }>('/staff/courses', { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeCourseProduct) }))
  },
  staffCourseRegistrations(token: string, courseId: string, status = '') {
    return request<{ items: BackendCourseRegistration[] }>(`/staff/courses/${encodeURIComponent(courseId)}/registrations${status ? `?status=${encodeURIComponent(status)}` : ''}`, { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeCourseRegistration) }))
  },
  createStaffCourseRegistration(token: string, courseId: string, payload: { passportNo?: string; phone?: string; note?: string; checkIn?: boolean; source?: string }) {
    return request<BackendCourseRegistration>(`/staff/courses/${encodeURIComponent(courseId)}/registrations`, { method: 'POST', header: bearer(token), data: payload })
      .then(normalizeCourseRegistration)
  },
  staffCourseRegistration(token: string, id: string) {
    return request<BackendCourseRegistration>(`/staff/course-registrations/${encodeURIComponent(id)}`, { header: bearer(token) })
      .then(normalizeCourseRegistration)
  },
  staffCourseManualCheckin(token: string, id: string, payload: { courseId?: string; source?: string; note?: string }) {
    return request<BackendCourseRegistration>(`/staff/course-registrations/${encodeURIComponent(id)}`, { method: 'POST', header: bearer(token), data: payload })
      .then(normalizeCourseRegistration)
  },
  staffCourseCheckinScan(token: string, payload: { courseId?: string; checkinCode: string; source?: string; note?: string }) {
    return request<BackendCourseRegistration>('/staff/course-checkins/scan', { method: 'POST', header: bearer(token), data: payload })
      .then(normalizeCourseRegistration)
  },
  staffTasks(token: string, params: { type?: string; status?: string; scope?: string; keyword?: string } = {}) {
    return request<{ items: BackendTask[] }>(`/staff/tasks${queryString(params)}`, { header: bearer(token) })
  },
  staffTask(token: string, id: string) {
    return request<BackendTask>(`/staff/tasks/${encodeURIComponent(id)}`, { header: bearer(token) })
  },
  updateStaffTask(token: string, id: string, payload: Record<string, unknown>) {
    return request<BackendTask>(`/staff/tasks/${encodeURIComponent(id)}`, { method: 'PATCH', header: bearer(token), data: payload })
  },
  staffConsultingRequests(token: string, params: { status?: string; scope?: string; keyword?: string } = {}) {
    return request<{ items: BackendConsultingRequest[] }>(`/staff/consulting-requests${queryString(params)}`, { header: bearer(token) })
  },
  staffConsultingRequest(token: string, id: string) {
    return request<BackendConsultingRequest>(`/staff/consulting-requests/${encodeURIComponent(id)}`, { header: bearer(token) })
  },
  updateStaffConsultingRequest(token: string, id: string, payload: Record<string, unknown>) {
    return request<BackendConsultingRequest>(`/staff/consulting-requests/${encodeURIComponent(id)}`, { method: 'PATCH', header: bearer(token), data: payload })
  },
  staffDataServiceRequests(token: string, params: { status?: string; scope?: string; keyword?: string } = {}) {
    return request<{ items: BackendDataServiceRequest[] }>(`/staff/data-service-requests${queryString(params)}`, { header: bearer(token) })
      .then((result) => ({ items: result.items.map(normalizeDataServiceRequest) }))
  },
  staffDataServiceRequest(token: string, id: string) {
    return request<BackendDataServiceRequest>(`/staff/data-service-requests/${encodeURIComponent(id)}`, { header: bearer(token) })
      .then(normalizeDataServiceRequest)
  },
  updateStaffDataServiceRequest(token: string, id: string, payload: Record<string, unknown>) {
    return request<BackendDataServiceRequest>(`/staff/data-service-requests/${encodeURIComponent(id)}`, { method: 'PATCH', header: bearer(token), data: payload })
      .then(normalizeDataServiceRequest)
  },
  staffOrders(token: string) {
    return request<{ items: BackendOrder[] }>('/staff/orders', { header: bearer(token) })
  },
  uploadStaffFile(token: string, filePath: string, fileName = '') {
    return upload<{ id: string; url: string; fileName: string; fileSize: number }>('/staff/uploads', token, filePath, fileName ? { fileName } : {})
  },
  previewCheckout(token: string, items: CartItem[]) {
    const expertBookingId = items.find((item) => item.expertBookingId)?.expertBookingId
    return request<BackendCheckoutPreview>('/checkout/preview', {
      method: 'POST',
      header: bearer(token),
      data: {
        expertBookingId,
        items: items.map((item) => ({
          productId: backendProductId(item),
          quantity: 1,
          billingCycle: item.billingCycle,
          expertBookingId: item.expertBookingId,
          dataServiceRequestId: item.dataServiceRequestId,
          consultingRequestId: item.consultingRequestId
        }))
      }
    })
  },
  createOrder(token: string, items: CartItem[], invoiceRequest?: BackendInvoiceRequest) {
    const expertBookingId = items.find((item) => item.expertBookingId)?.expertBookingId
    const dataServiceRequestId = items.find((item) => item.dataServiceRequestId)?.dataServiceRequestId
    const consultingRequestId = items.find((item) => item.consultingRequestId)?.consultingRequestId
    return request<BackendOrder>('/orders', {
      method: 'POST',
      header: bearer(token),
      data: {
        expertBookingId,
        dataServiceRequestId,
        consultingRequestId,
        invoiceRequest,
        items: items.map((item) => ({
          productId: backendProductId(item),
          quantity: 1,
          billingCycle: item.billingCycle,
          expertBookingId: item.expertBookingId,
          dataServiceRequestId: item.dataServiceRequestId,
          consultingRequestId: item.consultingRequestId
        }))
      }
    })
  },
  createPaymentOrder(token: string, orderNo: string, channel: BackendPaymentChannel = defaultPaymentChannel) {
    return request<{ paymentOrder: BackendPaymentOrder; order: BackendOrder }>('/payment-orders', {
      method: 'POST',
      header: bearer(token),
      data: { orderNo, channel }
    })
  },
  paymentStatus(token: string, paymentNo: string) {
    return request<{ paymentOrder: BackendPaymentOrder; order: BackendOrder; canRedirect: boolean }>(`/payment-orders/${encodeURIComponent(paymentNo)}/status`, { header: bearer(token) })
  },
  succeedDevPayment(paymentNo: string) {
    return request<{ order: BackendOrder }>(`/dev/payment-orders/${paymentNo}/succeed`, {
      method: 'POST',
      header: adminToken ? { 'x-admin-token': adminToken } : {}
    })
  },
  accountOrders(token: string) {
    return request<{ items: BackendOrder[] }>('/account/orders', { header: bearer(token) })
  },
  accountOrder(token: string, orderNo: string) {
    return request<BackendOrder>(`/account/orders/${encodeURIComponent(orderNo)}`, { header: 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',
      header: bearer(token),
      data: payload
    })
  },
  accountInvoiceApplications(token: string, status = '') {
    return request<{ items: BackendInvoiceApplication[] }>(`/account/invoice-applications${status ? `?status=${encodeURIComponent(status)}` : ''}`, { header: bearer(token) })
  },
  accountInvoiceApplication(token: string, invoiceNo: string) {
    return request<BackendInvoiceApplication>(`/account/invoice-applications/${encodeURIComponent(invoiceNo)}`, { header: bearer(token) })
  },
  accountTasks(token: string) {
    return request<{ items: BackendTask[] }>('/account/tasks', { header: bearer(token) })
  },
  accountTasksByType(token: string, type: ProductType) {
    return request<{ items: BackendTask[] }>(`/account/tasks?type=${encodeURIComponent(type)}`, { header: bearer(token) })
  },
  submitTaskMaterials(token: string, taskId: string, payload: Record<string, unknown>) {
    return request<BackendTask>(`/account/tasks/${taskId}/materials`, {
      method: 'PATCH',
      header: bearer(token),
      data: payload
    })
  }
}
