import supa from '@/components/supadb/aksupainstance.uts'
import type { AkReqResponse } from '@/uni_modules/ak-req/index.uts'
import { APP_ROLE, CURRENT_CLIENT, SUPA_KEY, SUPA_URL } from '@/ak/config.uts'
import { ORDER_PAY_TIMEOUT_SECONDS, ORDER_STATUS_CANCELLED, ORDER_STATUS_PAID_OR_SHIPPING, ORDER_STATUS_PENDING, ORDER_STATUS_TIMEOUT_LEGACY, ORDER_TIMEOUT_CANCEL_REASON, PAYMENT_STATUS_PAID, PAYMENT_STATUS_TIMEOUT, PAYMENT_STATUS_UNPAID, type UnifiedOrderSource } from '@/utils/orderStatus.uts'

// 导出 supa 实例，供 services 层统一使用
export { supa }
import type { OrderOptions } from '@/components/supadb/aksupa.uts'

const OLD_URL = '192.168.1.61:18000'
const NEW_URL = '119.146.131.237:9126'

function fixImageUrl(url: string | null): string {
  if (url == null) return ''
  if (url.indexOf(OLD_URL) >= 0) {
    return url.replace(OLD_URL, NEW_URL)
  }
  return url
}

function fixImageUrls(urls: any): string[] {
  if (urls == null) return []
  if (Array.isArray(urls)) {
    const result: string[] = []
    const arr = urls as any[]
    for (let i = 0; i < arr.length; i++) {
      try {
        const urlStr = JSON.stringify(arr[i])
        if (urlStr != null && urlStr.startsWith('"') && urlStr.endsWith('"')) {
          const fixed = fixImageUrl(urlStr.substring(1, urlStr.length - 1))
          if (fixed !== '') result.push(fixed)
        }
      } catch (e) {}
    }
    return result
  }
  return []
}

function canUseConsumerData(): boolean {
  return CURRENT_CLIENT === 'consumer' || CURRENT_CLIENT === 'full'
}

function maskConsumerKey(key: string): string {
  const keyLen = key.length
  if (keyLen <= 20) {
    return '(too short)'
  }
  return key.substring(0, 10) + '...' + key.substring(keyLen - 8)
}

function logConsumerQueryStart(action: string, tableName: string, fieldList: string = '*'): boolean {
  if (!canUseConsumerData()) {
    console.error('[consumer-db] 已阻止非 consumer 数据请求')
    console.error('[consumer-db] 当前端类型:', CURRENT_CLIENT)
    console.error('[consumer-db] 当前应用角色:', APP_ROLE)
    console.error('[consumer-db] 查询表:', tableName)
    console.error('[consumer-db] 查询动作:', action)
    return false
  }
  console.log('[consumer-db] 当前端类型:', CURRENT_CLIENT)
  console.log('[consumer-db] 当前应用角色:', APP_ROLE)
  console.log('[consumer-db] supabaseUrl 已加载:', SUPA_URL)
  console.log('[consumer-db] supabaseKey 已加载:', maskConsumerKey(SUPA_KEY))
  console.log('[consumer-db] 首页开始加载数据')
  console.log('[consumer-db] 查询表:', tableName)
  console.log('[consumer-db] 查询字段:', fieldList)
  console.log('[consumer-db] 查询动作:', action)
  return true
}

function logConsumerQuerySuccess(action: string, tableName: string, count: number): void {
  console.log('[consumer-db] 查询成功，动作:', action)
  console.log('[consumer-db] 查询成功，表:', tableName)
  console.log('[consumer-db] 查询成功，数量:', count)
}

function logConsumerQueryFailure(action: string, tableName: string, error: any): void {
  console.error('[consumer-db] 查询失败')
  console.error('[consumer-db] 查询动作:', action)
  console.error('[consumer-db] 查询表:', tableName)
  if (error != null) {
    try {
      console.error('[consumer-db] error.message:', error.message)
    } catch (e) {}
    try {
      console.error('[consumer-db] error.code:', error.code)
    } catch (e) {}
    try {
      console.error('[consumer-db] error.details:', error.details)
    } catch (e) {}
    try {
      console.error('[consumer-db] error.hint:', error.hint)
    } catch (e) {}
  }
  console.error('[consumer-db] error.raw:', error)
}

// 使用单例 Supabase 客户端
// const supa = createClient(SUPA_URL, SUPA_KEY)

// 辅助函数：安全获取字符串值
function safeGetString(obj: UTSJSONObject, key: string): string {
  try {
    const rawVal = obj.get(key)
    if (rawVal == null) return ''
    const strVal = JSON.stringify(rawVal)
    if (strVal == null) return ''
    if (strVal.startsWith('"') && strVal.endsWith('"')) {
      return strVal.substring(1, strVal.length - 1)
    }
    return strVal
  } catch (e) {
    console.error('safeGetString error for key:', key, e)
    return ''
  }
}

// 辅助函数：安全获取数值
function safeGetNumber(obj: UTSJSONObject, key: string): number {
  try {
    const rawVal = obj.get(key)
    if (rawVal == null) return 0
    try {
      const numVal = rawVal as number
      if (!isNaN(numVal)) return numVal
    } catch (e) {}
    return 0
  } catch (e) {
    console.error('safeGetNumber error for key:', key, e)
    return 0
  }
}

// 辅助函数：安全获取布尔值
function safeGetBoolean(obj: UTSJSONObject, key: string): boolean {
  try {
    const rawVal = obj.get(key)
    if (rawVal == null) return false
    try {
      const boolVal = rawVal as boolean
      return boolVal
    } catch (e) {}
    return false
  } catch (e) {
    console.error('safeGetBoolean error for key:', key, e)
    return false
  }
}

// 辅助函数：安全获取字符串数组
function safeGetStringArray(obj: UTSJSONObject, key: string): string[] {
  try {
    const rawVal = obj.get(key)
    if (rawVal != null && Array.isArray(rawVal)) {
      return rawVal as string[]
    }
    return [] as string[]
  } catch (e) {
    console.error('safeGetStringArray error for key:', key, e)
    return [] as string[]
  }
}

// 辅助函数：从原始数据解析商品
function parseProductFromRaw(item: any): Product {
  try {
    console.log('[parseProductFromRaw] 开始解析商品')
    const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
    console.log('[parseProductFromRaw] JSON转换成功')
    
    const mainImageUrl = fixImageUrl(safeGetString(itemObj, 'main_image_url'))
    const imageUrls = fixImageUrls(safeGetStringArray(itemObj, 'image_urls'))
    console.log('[parseProductFromRaw] 图片处理完成')
    
    const result: Product = {
      id: safeGetString(itemObj, 'id'),
      name: safeGetString(itemObj, 'name'),
      short_title: safeGetString(itemObj, 'short_title'),
      subtitle: safeGetString(itemObj, 'subtitle'),
      description: safeGetString(itemObj, 'description'),
      base_price: safeGetNumber(itemObj, 'base_price'),
      price: safeGetNumber(itemObj, 'base_price'),
      original_price: safeGetNumber(itemObj, 'market_price'),
      market_price: safeGetNumber(itemObj, 'market_price'),
      main_image_url: mainImageUrl,
      image_url: mainImageUrl,
      images: imageUrls,
      category_id: safeGetString(itemObj, 'category_id'),
      brand_id: safeGetString(itemObj, 'brand_id'),
      merchant_id: safeGetString(itemObj, 'merchant_id'),
      total_stock: safeGetNumber(itemObj, 'total_stock'),
      stock: safeGetNumber(itemObj, 'total_stock'),
      sale_count: safeGetNumber(itemObj, 'sale_count'),
      status: safeGetNumber(itemObj, 'status'),
      is_featured: safeGetBoolean(itemObj, 'is_featured'),
      is_new: safeGetBoolean(itemObj, 'is_new'),
      is_hot: safeGetBoolean(itemObj, 'is_hot'),
      card_tags: safeGetStringArray(itemObj, 'card_tags'),
      service_tags: safeGetStringArray(itemObj, 'service_tags'),
      selling_points: safeGetStringArray(itemObj, 'selling_points'),
      display_sales_text: safeGetString(itemObj, 'display_sales_text'),
      compliance_type: safeGetString(itemObj, 'compliance_type'),
      device_class: safeGetString(itemObj, 'device_class'),
      specification: safeGetString(itemObj, 'specification'),
      usage: safeGetString(itemObj, 'usage'),
      side_effects: safeGetString(itemObj, 'side_effects'),
      precautions: safeGetString(itemObj, 'precautions'),
      expiry_date: safeGetString(itemObj, 'expiry_date'),
      storage_conditions: safeGetString(itemObj, 'storage_conditions'),
      approval_number: safeGetString(itemObj, 'approval_number'),
      created_at: safeGetString(itemObj, 'created_at')
    }
    console.log('[parseProductFromRaw] 商品解析成功:', result.name)
    return result
  } catch (e) {
    console.error('parseProductFromRaw error:', e)
    return {
      id: '',
      name: '',
      description: '',
      base_price: 0,
      price: 0,
      original_price: 0,
      market_price: 0,
      main_image_url: '',
      image_url: '',
      images: [] as string[],
      category_id: '',
      brand_id: '',
      merchant_id: '',
      total_stock: 0,
      stock: 0,
      sale_count: 0,
      status: 0,
      is_featured: false,
      is_new: false,
      is_hot: false,
      specification: '',
      usage: '',
      side_effects: '',
      precautions: '',
      expiry_date: '',
      storage_conditions: '',
      approval_number: '',
      created_at: ''
    } as Product
  }
}

// 类型定义
export type Brand = {
  id: string
  name: string
  logo_url: string
  description: string
}

export type Category = {
  id: string
  name: string
  icon: string
  description: string
  color: string
  parent_id?: string
  level?: number
  slug?: string
  sort_order?: number
  image_url?: string
  scene?: string
  category_type?: string
  compliance_type?: string
  is_active?: boolean
  created_at?: string
}

export type Product = {
  id: string
  category_id: string
  merchant_id: string
  name: string
  subtitle?: string
  description?: string
  base_price?: number
  market_price?: number
  cost_price?: number
  main_image_url?: string
  image_url?: string
  image_urls?: string
  video_urls?: string
  images?: string[]
  sale_count?: number
  view_count?: number
  total_stock?: number
  available_stock?: number
  is_hot?: boolean
  is_new?: boolean
  is_featured?: boolean
  status?: number
  rating_avg?: number
  rating_count?: number
  rating?: number
  review_count?: number
  brand_id?: string
  shop_id?: string
  tags?: string
  attributes?: string
  short_title?: string
  card_tags?: string[]
  service_tags?: string[]
  selling_points?: string[]
  display_sales_text?: string
  compliance_type?: string
  device_class?: string
  specification?: string
  usage?: string
  side_effects?: string
  precautions?: string
  expiry_date?: string
  storage_conditions?: string
  approval_number?: string
  created_at?: string
  updated_at?: string
  price?: number
  original_price?: number
  stock?: number
  sales?: number
  cover?: string
  brand_name?: string
  category_name?: string
  shop_name?: string
  merchant_name?: string
}

export type Shop = {
  id: string
  merchant_id: string
  shop_name: string
  shop_logo?: string
  shop_banner?: string
  description?: string
  contact_name?: string
  contact_phone?: string
  rating_avg?: number
  total_sales?: number
  product_count?: number
  total_sales_count?: number
  created_at?: string
}

export type CartItem = {
  id: string
  user_id: string
  product_id: string
  sku_id?: string
  merchant_id?: string
  quantity: number
  selected: boolean
  product_name?: string
  product_image?: string
  product_price?: number
  product_specification?: string
  shop_id?: string
  shop_name?: string
  created_at?: string
  updated_at?: string
}

export type UserAddress = {
  id: string
  user_id: string
  recipient_name: string
  phone: string
  province: string
  city: string
  district: string
  detail_address: string
  postal_code?: string
  is_default: boolean
  label?: string
  latitude?: number
  longitude?: number
  coordinate_type?: string
  created_at?: string
  updated_at?: string
}

export type UserCoupon = {
  id: string
  user_id: string
  template_id: string
  coupon_code: string
  status: number // 1: unused, 2: used, 3: expired
  received_at: string
  expire_at: string
  used_at?: string
  // join fields from template or view
  template_name?: string
  amount?: number
  min_spend?: number
  name?: string
  title?: string
}

export type ChatRoom = {
  id: string
  user_id: string
  merchant_id: string
  shop_name: string
  shop_logo?: string
  last_message?: string
  last_message_at?: string
  unread_count: number
  is_top: boolean
  created_at?: string
  updated_at?: string
}

export type Notification = {
  id: string
  user_id: string
  type: string
  title: string
  content: string
  icon_url?: string
  link_url?: string
  is_read: boolean
  extra_data?: string
  created_at?: string
}

export type ChatMessage = {
  id: string
  session_id?: string
  sender_id?: string
  receiver_id?: string
  content: string
  msg_type: string
  is_read: boolean
  is_from_user: boolean
  extra_data?: string
  created_at?: string
}

export type PaginatedResponse<T> = {
  data: T[]
  total: number
  page: number
  limit: number
  hasmore: boolean
}

export type ProductSku = {
  id: string
  product_id: string
  sku_code: string
  specifications: string // JSON string
  price: number
  market_price?: number
  cost_price?: number
  stock?: number
  warning_stock?: number
  image_url?: string
  weight?: number
  status?: number
  created_at?: string
}

export type AddAddressParams = {
  recipient_name: string
  phone: string
  province: string
  city: string
  district: string
  detail_address: string
  postal_code?: string
  is_default?: boolean
  label?: string
  latitude?: number
  longitude?: number
  coordinate_type?: string
}

export type UpdateAddressParams = {
  recipient_name?: string
  phone?: string
  province?: string
  city?: string
  district?: string
  detail_address?: string
  postal_code?: string
  is_default?: boolean
  label?: string
  latitude?: number
  longitude?: number
  coordinate_type?: string
}

export type CreateOrderParams = {
  merchant_id: string
  product_amount: number
  shipping_fee: number
  total_amount: number
  shipping_address: any
  items: any[]
}

export type ShopOrderParams = {
  shipping_address: any
  shopGroups: any[]
  deliveryFee: number
  discountAmount: number
}

function emptyProductPage(page: number, limit: number): PaginatedResponse<Product> {
  return {
    data: [] as Product[],
    total: 0,
    page,
    limit,
    hasmore: false
  }
}

function buildAnyStringList(values: string[]): any[] {
  const result: any[] = []
  for (let i = 0; i < values.length; i++) {
    if (values[i] != '') {
      result.push(values[i])
    }
  }
  return result
}

function parseMedicalMallCategory(item: UTSJSONObject): Category {
  const icon = safeGetString(item, 'icon')
  const imageUrl = safeGetString(item, 'image_url')
  const color = safeGetString(item, 'color')
  return {
    id: safeGetString(item, 'id'),
    name: safeGetString(item, 'name'),
    icon: icon != '' ? icon : imageUrl,
    description: safeGetString(item, 'description'),
    color: color != '' ? color : '#16a085',
    parent_id: safeGetString(item, 'parent_id'),
    level: safeGetNumber(item, 'level'),
    slug: safeGetString(item, 'category_type'),
    sort_order: safeGetNumber(item, 'sort_order'),
    image_url: imageUrl,
    scene: safeGetString(item, 'scene'),
    category_type: safeGetString(item, 'category_type'),
    compliance_type: safeGetString(item, 'compliance_type'),
    is_active: safeGetBoolean(item, 'is_active'),
    created_at: safeGetString(item, 'created_at')
  } as Category
}

function getMedicalMallCategoryKeywords(categoryId: string): string[] {
  if (categoryId == 'med_device') return ['医疗器械', '血压计', '血糖仪', '血氧仪', '体温计', '制氧机', '雾化器', '轮椅', '拐杖', '护理床']
  if (categoryId == 'blood_pressure_monitor') return ['血压计', '血压监测', '电子血压计']
  if (categoryId == 'blood_glucose_meter') return ['血糖仪', '血糖测试', '采血笔']
  if (categoryId == 'oximeter') return ['血氧仪', '血氧']
  if (categoryId == 'thermometer') return ['体温计', '额温枪', '测温']
  if (categoryId == 'oxygen_concentrator') return ['制氧机', '吸氧']
  if (categoryId == 'nebulizer') return ['雾化器', '雾化']
  if (categoryId == 'wheelchair_crutch') return ['轮椅', '拐杖', '助行器']
  if (categoryId == 'nursing_bed') return ['护理床', '病床']

  if (categoryId == 'otc_medicine') return ['感冒药', '退烧药', '止咳', '咽喉', '肠胃', '皮肤', '止痛', '跌打', '儿童用药', '家庭常备药']
  if (categoryId == 'cold_fever') return ['感冒药', '退烧', '发烧', '退热贴', '感冒']
  if (categoryId == 'cough_throat') return ['咳嗽', '咽喉', '润喉']
  if (categoryId == 'stomach_medicine') return ['肠胃', '胃药', '益生菌']
  if (categoryId == 'skin_external') return ['皮肤', '外用', '软膏', '喷剂']
  if (categoryId == 'eye_ear_nose') return ['眼药', '滴眼', '鼻炎', '口腔', '耳']
  if (categoryId == 'pain_relief') return ['止痛', '镇痛']
  if (categoryId == 'trauma_sprain') return ['跌打', '扭伤', '损伤', '喷雾']
  if (categoryId == 'child_medicine') return ['儿童', '小儿']

  if (categoryId == 'rehab_care') return ['康复', '护理', '敷料', '护具', '支具', '理疗', '热敷', '训练']
  if (categoryId == 'postop_rehab') return ['术后', '恢复带', '康复']
  if (categoryId == 'wound_dressing' || categoryId == 'wound_care') return ['伤口', '敷料', '纱布', '创可贴', '护理包']
  if (categoryId == 'brace_support') return ['护具', '支具', '护腰', '护膝', '支撑带']
  if (categoryId == 'rehab_training') return ['康复训练', '训练器']
  if (categoryId == 'physiotherapy_hot') return ['理疗', '热敷', '暖贴', '热敷贴']
  if (categoryId == 'mobility_training') return ['行动训练', '步行训练']

  if (categoryId == 'chronic_monitor') return ['慢病', '血压', '血糖', '心脑血管', '呼吸', '体脂', '家庭检测']
  if (categoryId == 'hypertension') return ['高血压', '血压']
  if (categoryId == 'diabetes') return ['糖尿病', '血糖']
  if (categoryId == 'cardiovascular') return ['心脑血管', '心率', '心电']
  if (categoryId == 'respiratory_health') return ['呼吸', '雾化', '氧', '制氧']
  if (categoryId == 'weight_bodyfat') return ['体重', '体脂']
  if (categoryId == 'home_testing') return ['检测', '试纸']

  if (categoryId == 'elderly_aid') return ['适老', '长者', '防滑', '扶手', '助浴', '失禁', '生活辅助']
  if (categoryId == 'anti_slip') return ['防滑', '防跌']
  if (categoryId == 'elderly_bathroom') return ['卫浴', '扶手', '浴室']
  if (categoryId == 'eating_aid') return ['助餐', '餐具']
  if (categoryId == 'bathing_aid') return ['助浴', '洗澡椅', '沐浴']
  if (categoryId == 'incontinence_care') return ['失禁', '护理垫', '纸尿裤']
  if (categoryId == 'daily_living_aid') return ['生活辅助', '起身', '坐便']

  if (categoryId == 'nutrition_health') return ['维生素', '钙片', '蛋白粉', '营养', '益生菌', '免疫']
  if (categoryId == 'vitamin') return ['维生素', '维C', '维D']
  if (categoryId == 'calcium') return ['钙片', '钙', '钙铁锌', '锌', '硒']
  if (categoryId == 'protein') return ['蛋白', '蛋白粉']
  if (categoryId == 'elderly_nutrition') return ['老人营养', '中老年营养']
  if (categoryId == 'gut_health') return ['益生菌', '肠道']
  if (categoryId == 'immune_support') return ['免疫', '免疫支持']

  if (categoryId == 'protection_disinfection') return ['口罩', '消毒', '酒精', '湿巾', '手套', '急救包', '棉签', '纱布']
  if (categoryId == 'mask') return ['口罩']
  if (categoryId == 'disinfectant') return ['消毒液', '消毒', '酒精']
  if (categoryId == 'alcohol_wipes') return ['酒精湿巾', '湿巾']
  if (categoryId == 'gloves') return ['手套']
  if (categoryId == 'first_aid') return ['急救包']
  if (categoryId == 'dressing_tools' || categoryId == 'nursing_consumables') return ['棉签', '纱布', '耗材']

  if (categoryId == 'tcm_health') return ['中医', '艾灸', '拔罐', '养生茶', '贴敷', '药膳', '按摩', '泡脚']
  if (categoryId == 'moxibustion') return ['艾灸', '拔罐', '艾条', '温灸']
  if (categoryId == 'herbal_drink') return ['养生茶', '茶饮', '草本']
  if (categoryId == 'tcm_patch') return ['贴敷', '理疗贴', '草本贴']
  if (categoryId == 'medicated_diet') return ['药膳', '滋补']
  if (categoryId == 'massage_tools') return ['按摩', '理疗', '刮痧']
  if (categoryId == 'foot_bath') return ['泡脚', '足浴']

  if (categoryId == 'home_care_daily') return ['护理', '伤口', '口腔', '皮肤', '清洁', '耗材', '健康工具']
  if (categoryId == 'oral_care') return ['口腔', '牙', '漱口']
  if (categoryId == 'skin_care') return ['皮肤护理', '修护', '护肤']
  if (categoryId == 'cleaning_care') return ['清洁护理', '清洁']
  if (categoryId == 'home_health_tool') return ['健康工具', '家庭健康']

  if (categoryId == 'all_medical' || categoryId == 'recommend') return ['血压计', '血糖仪', '血氧仪', '体温计', '制氧机', '雾化器', '轮椅', '护理床', '感冒药', '退热贴', '止咳', '胃药', '创可贴', '敷料', '纱布', '护具', '康复', '理疗', '慢病', '口罩', '消毒', '酒精', '急救包', '艾灸', '拔罐', '维生素', '钙片', '蛋白粉', '益生菌', '老人营养', '适老', '助浴', '护理']
  return [] as string[]
}

function containsMedicalMallKeyword(source: string, keywords: string[]): boolean {
  if (source == '' || keywords.length == 0) {
    return false
  }
  for (let i = 0; i < keywords.length; i++) {
    if (keywords[i] != '' && source.indexOf(keywords[i]) != -1) {
      return true
    }
  }
  return false
}

function buildMedicalMallProductText(item: UTSJSONObject): string {
  const tags = safeGetStringArray(item, 'tags')
  let tagText = ''
  for (let i = 0; i < tags.length; i++) {
    if (tags[i] != '') {
      tagText += ' ' + tags[i]
    }
  }
  return (
    safeGetString(item, 'name') + ' ' +
    safeGetString(item, 'subtitle') + ' ' +
    safeGetString(item, 'description') + ' ' +
    safeGetString(item, 'category_name') + ' ' +
    safeGetString(item, 'specification') + ' ' +
    safeGetString(item, 'usage') + ' ' +
    tagText
  )
}

function isRxHiddenProduct(item: UTSJSONObject): boolean {
  return safeGetString(item, 'compliance_type') == 'rx_hidden'
}

function matchesMedicalMallFallback(item: UTSJSONObject, categoryId: string): boolean {
  if (isRxHiddenProduct(item)) {
    return false
  }
  const sourceText = buildMedicalMallProductText(item)
  return containsMedicalMallKeyword(sourceText, getMedicalMallCategoryKeywords(categoryId))
}

function sortProductsByIdOrder(products: Product[], orderedIds: string[]): Product[] {
  const productMap = new Map<string, Product>()
  for (let i = 0; i < products.length; i++) {
    productMap.set(products[i].id, products[i])
  }
  const sorted: Product[] = []
  for (let i = 0; i < orderedIds.length; i++) {
    const item = productMap.get(orderedIds[i])
    if (item != null) {
      sorted.push(item)
    }
  }
  return sorted
}

function dedupeProducts(products: Product[]): Product[] {
  const deduped: Product[] = []
  const seenIds: string[] = []
  for (let i = 0; i < products.length; i++) {
    const productId = products[i].id
    if (productId != '' && seenIds.indexOf(productId) != -1) {
      continue
    }
    if (productId != '') {
      seenIds.push(productId)
    }
    deduped.push(products[i])
  }
  return deduped
}

export type ShopOrderResponse = {
  success: boolean
  orderIds: string[]
  error?: string
}

export type RefundResponse = {
  success: boolean
  message: string
}

export type ConfirmReceiptResponse = {
  success: boolean
  error?: string
}

export type GetOrdersByCursorParams = {
  cursor: string
  limit: number
  status: number
  keyword: string
}

export type GetOrdersByCursorResult = {
  list: UTSJSONObject[]
  nextCursor: string
  hasMore: boolean
}

export type GetUnifiedOrdersByCursorParams = {
  cursor: string
  limit: number
  bizType: string
  statusTab: string
  keyword: string
}

export type GetUnifiedOrdersByCursorResult = {
  list: UTSJSONObject[]
  nextCursor: string
  hasMore: boolean
}

export type OrderCountsResult = {
  all: number
  pending: number
  shipping: number
  delivering: number
  completed: number
  aftersale: number
  cancelled: number
}

class SupabaseService {
  // 获取当前用户ID
  public getCurrentUserId(): string | null {
    try {
      // 1. 优先从 Supabase 会话获取
      const session = supa.getSession()
      if (session != null && session.user != null) {
        return session.user.getString('id')
      }
      
      // 移除基于 storage 的后备获取，严格只认当前 Tab 独立 session
      return null

      //cyh
      // 2. 尝试从 Storage 恢复 Session (针对 App 重启后内存丢失的情况)
      // 注意：这里无法异步调用 hydrate，所以只能依赖 UI 层或 init 层的预加载
      // 但我们可以返回本地存储 ID 作为 fallback，前提是 Token 有效
      
      // 后备：尝试从本地存储获取
      // const userId = uni.getStorageSync('user_id')
      // return userId != null ? userId as string : null
      
    } catch (e) {
      console.error('获取用户ID失败:', e)
      return null
    }
  }

  // 确保会话有效 (异步)
  async ensureSession(): Promise<string | null> {
      let session = supa.getSession()
      if (session.user == null) {
          console.log('Session user is null, attempting to hydrate from storage...')
          await supa.hydrateSessionFromStorage()
          session = supa.getSession()
      }
      
      if (session.user != null) {
          // 同步 user_id 到 storage 保持一致
          const uid = session.user!!.getString('id')
          if (uid != null) {
             uni.setStorageSync('user_id', uid)
             return uid
          }
      }
      return this.getCurrentUserId()
  }

  // 获取所有分类
  async getCategories(): Promise<Category[]> {
    try {
      const response = await supa
        .from('ml_categories')
        .select('*')
        .order('name', { ascending: true })
        .execute()
      
      if (response.error != null) {
        console.error('获取分类失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) {
        return []
      }
      
      const categories: Category[] = []
      const rawList = rawData as any[]
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const catObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        const idVal = catObj.get('id')
        const nameVal = catObj.get('name')
        const iconVal = catObj.get('icon')
        const iconUrlVal = catObj.get('icon_url')
        const descVal = catObj.get('description')
        const colorVal = catObj.get('color')
        const parentIdVal = catObj.get('parent_id')
        const levelVal = catObj.get('level')
        
        const cat: Category = {
          id: (typeof idVal == 'string') ? (idVal as string) : '',
          name: (typeof nameVal == 'string') ? (nameVal as string) : '',
          icon: (typeof iconVal == 'string') ? (iconVal as string) : ((typeof iconUrlVal == 'string') ? (iconUrlVal as string) : ''),
          description: (typeof descVal == 'string') ? (descVal as string) : '',
          color: (typeof colorVal == 'string') ? (colorVal as string) : '#4CAF50',
          parent_id: (typeof parentIdVal == 'string') ? (parentIdVal as string) : null,
          level: (typeof levelVal == 'number') ? (levelVal as number) : 0
        } as Category
        categories.push(cat)
      }
      return categories
    } catch (error) {
      console.error('获取分类异常:', error)
      return []
    }
  }

  // 根据ID获取单个分类
  async getCategoryById(categoryId: string): Promise<Category | null> {
    try {
      const response = await supa
        .from('ml_categories')
        .select('*')
        .eq('id', categoryId)
        .limit(1)
        .execute()
      
      if (response.error != null) {
        console.error('获取分类失败:', response.error)
        return null
      }
      
      const rawData = response.data
      if (rawData == null) {
        return null
      }
      
      // 处理数组返回值
      const rawList = rawData as any[]
      if (rawList.length == 0) {
        return null
      }
      
      const item = rawList[0]
      const catObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
      const idVal = catObj.get('id')
      const nameVal = catObj.get('name')
      const iconVal = catObj.get('icon')
      const iconUrlVal = catObj.get('icon_url')
      const descVal = catObj.get('description')
      const colorVal = catObj.get('color')
      const parentIdVal = catObj.get('parent_id')
      const levelVal = catObj.get('level')
      
      const cat: Category = {
        id: (typeof idVal == 'string') ? (idVal as string) : '',
        name: (typeof nameVal == 'string') ? (nameVal as string) : '',
        icon: (typeof iconVal == 'string') ? (iconVal as string) : ((typeof iconUrlVal == 'string') ? (iconUrlVal as string) : ''),
        description: (typeof descVal == 'string') ? (descVal as string) : '',
        color: (typeof colorVal == 'string') ? (colorVal as string) : '#4CAF50',
        parent_id: (typeof parentIdVal == 'string') ? (parentIdVal as string) : null,
        level: (typeof levelVal == 'number') ? (levelVal as number) : 0
      } as Category
      return cat
    } catch (error) {
      console.error('获取分类异常:', error)
      return null
    }
  }

  // 获取一级分类
  async getParentCategories(): Promise<Category[]> {
    try {
      if (!logConsumerQueryStart('getParentCategories', 'ml_categories', '*')) {
        return []
      }
      const response = await supa
        .from('ml_categories')
        .select('*')
        .eq('level', 1)
        .order('sort_order', { ascending: true })
        .execute()
      
      if (response.error != null) {
        logConsumerQueryFailure('getParentCategories', 'ml_categories', response.error)
        console.error('获取一级分类失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) {
        return []
      }

      const categories: Category[] = []
      const rawList = rawData as Array<UTSJSONObject>
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const icon = this.getCategoryIcon(item)
        
        // 安全获取属性
        const idVal = item['id']
        const nameVal = item['name']
        const descVal = item['description']
        const colorVal = item['color']
        const slugVal = item['slug']
        
        const cat: Category = {
          id: (typeof idVal == 'string') ? (idVal as string) : '',
          name: (typeof nameVal == 'string') ? (nameVal as string) : '',
          icon: icon,
          description: (typeof descVal == 'string') ? (descVal as string) : '',
          color: (typeof colorVal == 'string') ? (colorVal as string) : '#ff5000',
          level: 1,
          slug: (typeof slugVal == 'string') ? (slugVal as string) : ''
        }
        categories.push(cat)
      }
      logConsumerQuerySuccess('getParentCategories', 'ml_categories', categories.length)
      return categories
    } catch (error) {
      logConsumerQueryFailure('getParentCategories', 'ml_categories', error)
      console.error('获取一级分类异常:', error)
      return []
    }
  }

  // 获取子分类
  async getSubCategories(parentId: string): Promise<Category[]> {
    try {
      if (!logConsumerQueryStart('getSubCategories', 'ml_categories', '*')) {
        return []
      }
      console.log('[getSubCategories] 开始获取子分类, parentId:', parentId)
      const response = await supa
        .from('ml_categories')
        .select('*')
        .eq('level', 2)
        .eq('parent_id', parentId)
        .order('sort_order', { ascending: true })
        .execute()
      
      console.log('[getSubCategories] 查询完成')
      
      if (response.error != null) {
        logConsumerQueryFailure('getSubCategories', 'ml_categories', response.error)
        console.error('获取子分类失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) {
        console.log('[getSubCategories] 数据为空')
        return []
      }

      const categories: Category[] = []
      const rawList = rawData as UTSJSONObject[]
      console.log('[getSubCategories] 原始数据条数:', rawList.length)
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        const icon = this.getCategoryIcon(itemObj)
        const cat: Category = {
          id: safeGetString(itemObj, 'id'),
          name: safeGetString(itemObj, 'name'),
          icon: icon,
          description: safeGetString(itemObj, 'description'),
          color: safeGetString(itemObj, 'color').length > 0 ? safeGetString(itemObj, 'color') : '#ff5000',
          level: 2,
          parent_id: safeGetString(itemObj, 'parent_id'),
          slug: safeGetString(itemObj, 'slug')
        }
        categories.push(cat)
      }
      console.log('[getSubCategories] 返回分类数量:', categories.length)
      logConsumerQuerySuccess('getSubCategories', 'ml_categories', categories.length)
      return categories
    } catch (error) {
      logConsumerQueryFailure('getSubCategories', 'ml_categories', error)
      console.error('获取子分类异常:', error)
      return []
    }
  }

  // 获取分类图标的辅助方法
  getCategoryIcon(item: UTSJSONObject): string {
    const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
    const icon = safeGetString(itemObj, 'icon')
    if (icon.length > 0) {
      return icon
    }
    const iconUrl = safeGetString(itemObj, 'icon_url')
    if (iconUrl.length > 0) {
      return iconUrl
    }
    const name = safeGetString(itemObj, 'name')
    if (name.includes('数码') || name.includes('电器') || name.includes('手机')) return '📱'
    if (name.includes('服装') || name.includes('衣服') || name.includes('鞋')) return '👕'
    if (name.includes('食品') || name.includes('水果') || name.includes('零食')) return '🍎'
    if (name.includes('美妆') || name.includes('护肤') || name.includes('化妆')) return '💄'
    if (name.includes('母婴') || name.includes('婴儿') || name.includes('儿童')) return '👶'
    if (name.includes('家居') || name.includes('家具') || name.includes('装饰')) return '🏠'
    if (name.includes('图书') || name.includes('文具')) return '📚'
    if (name.includes('运动') || name.includes('户外') || name.includes('健身')) return '⚽'
    if (name.includes('医药') || name.includes('保健') || name.includes('健康')) return '💊'
    return '📦'
  }

  // 获取所有品牌
  async getBrands(): Promise<Brand[]> {
    try {
      if (!logConsumerQueryStart('getBrands', 'ml_brands', 'id, name, logo_url, description, is_active')) {
        return []
      }
      console.log('[getBrands] 开始获取品牌数据...')
      const response = await supa
        .from('ml_brands')
        .select('id, name, logo_url, description, is_active')
        .order('name', { ascending: true })
        .execute()
      
      if (response.error != null) {
        logConsumerQueryFailure('getBrands', 'ml_brands', response.error)
        console.error('获取品牌失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) {
        console.log('[getBrands] 数据为空')
        return []
      }
      
      const brands: Brand[] = []
      const rawList = rawData as any[]
      console.log('[getBrands] 数据条数:', rawList.length)
      
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const brandObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        const idVal = brandObj.get('id')
        const nameVal = brandObj.get('name')
        const logoVal = brandObj.get('logo_url')
        const descVal = brandObj.get('description')
        const isActiveVal = brandObj.get('is_active')
        
        let isActiveBool: boolean = true
        if (isActiveVal != null) {
          if (typeof isActiveVal == 'boolean') {
            isActiveBool = isActiveVal as boolean
          } else if (typeof isActiveVal == 'number') {
            isActiveBool = (isActiveVal as number) === 1
          }
        }
        if (!isActiveBool) {
          continue
        }
        
        const brand: Brand = {
          id: (typeof idVal == 'string') ? (idVal as string) : '',
          name: (typeof nameVal == 'string') ? (nameVal as string) : '',
          logo_url: (typeof logoVal == 'string') ? (logoVal as string) : '',
          description: (typeof descVal == 'string') ? (descVal as string) : ''
        } as Brand
        brands.push(brand)
      }
      console.log('[getBrands] 返回品牌数量:', brands.length)
      logConsumerQuerySuccess('getBrands', 'ml_brands', brands.length)
      return brands
    } catch (error) {
      logConsumerQueryFailure('getBrands', 'ml_brands', error)
      console.error('获取品牌异常:', error)
      return []
    }
  }

  // 获取指定分类的商品
  async getProductsByCategory(
    categoryId: string, 
    page: number = 1, 
    limit: number = 20
  ): Promise<PaginatedResponse<Product>> {
    try {
      if (!logConsumerQueryStart('getProductsByCategory', 'ml_products_detail_view', '*')) {
        return emptyProductPage(page, limit)
      }
      console.log('[getProductsByCategory] 开始查询，分类ID:', categoryId, '页码:', page)
      
      // 在数据库层面进行分类过滤
      const response = await supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('category_id', categoryId)
        .eq('status', '1')  // 使用字符串 '1' 而不是整数 1
        .order('sale_count', { ascending: false })
        .page(page)
        .limit(limit)
        .execute()
      
      console.log('[getProductsByCategory] 查询完成，total:', response.total)
      
      if (response.error != null) {
        logConsumerQueryFailure('getProductsByCategory', 'ml_products_detail_view', response.error)
        console.error('获取商品失败:', response.error)
        return {
          data: [] as Product[],
          total: 0,
          page,
          limit,
          hasmore: false
        }
      }
      
      const rawData = response.data
      if (rawData == null) {
        return {
          data: [] as Product[],
          total: 0,
          page,
          limit,
          hasmore: false
        }
      }
      
      const products: Product[] = []
      const rawList = rawData as any[]
      console.log('[getProductsByCategory] 返回数据条数:', rawList.length)
      
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        products.push(parseProductFromRaw(item))
      }
      logConsumerQuerySuccess('getProductsByCategory', 'ml_products_detail_view', products.length)
      
      return {
        data: products,
        total: response.total ?? products.length,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
      logConsumerQueryFailure('getProductsByCategory', 'ml_products_detail_view', error)
      console.error('获取商品异常:', error)
      return {
        data: [] as Product[],
        total: 0,
        page,
        limit,
        hasmore: false
      }
    }
  }

  async getMedicalMallParentCategories(): Promise<Category[]> {
    try {
      if (!logConsumerQueryStart('getMedicalMallParentCategories', 'medical_mall_categories', '*')) {
        return []
      }
      const response = await supa
        .from('medical_mall_categories')
        .select('*')
        .is('parent_id', null)
        .eq('is_active', true)
        .is('deleted_at', null)
        .order('sort_order', { ascending: true })
        .execute()

      if (response.error != null || response.data == null) {
        logConsumerQueryFailure('getMedicalMallParentCategories', 'medical_mall_categories', response.error)
        return []
      }

      const rows = response.data as UTSJSONObject[]
      const categories: Category[] = []
      for (let i = 0; i < rows.length; i++) {
        categories.push(parseMedicalMallCategory(JSON.parse(JSON.stringify(rows[i])) as UTSJSONObject))
      }
      logConsumerQuerySuccess('getMedicalMallParentCategories', 'medical_mall_categories', categories.length)
      return categories
    } catch (error) {
      logConsumerQueryFailure('getMedicalMallParentCategories', 'medical_mall_categories', error)
      return []
    }
  }

  async getMedicalMallCategoryById(categoryId: string): Promise<Category | null> {
    try {
      if (categoryId == '') {
        return null
      }
      const response = await supa
        .from('medical_mall_categories')
        .select('*')
        .eq('id', categoryId)
        .eq('is_active', true)
        .is('deleted_at', null)
        .limit(1)
        .execute()

      if (response.error != null || response.data == null) {
        logConsumerQueryFailure('getMedicalMallCategoryById', 'medical_mall_categories', response.error)
        return null
      }

      const rows = response.data as UTSJSONObject[]
      if (rows.length == 0) {
        return null
      }

      return parseMedicalMallCategory(JSON.parse(JSON.stringify(rows[0])) as UTSJSONObject)
    } catch (error) {
      logConsumerQueryFailure('getMedicalMallCategoryById', 'medical_mall_categories', error)
      return null
    }
  }

  async getMedicalMallSubCategories(parentId: string): Promise<Category[]> {
    try {
      if (!logConsumerQueryStart('getMedicalMallSubCategories', 'medical_mall_categories', '*')) {
        return []
      }
      const response = await supa
        .from('medical_mall_categories')
        .select('*')
        .eq('parent_id', parentId)
        .eq('is_active', true)
        .is('deleted_at', null)
        .order('sort_order', { ascending: true })
        .execute()

      if (response.error != null || response.data == null) {
        logConsumerQueryFailure('getMedicalMallSubCategories', 'medical_mall_categories', response.error)
        return []
      }

      const rows = response.data as UTSJSONObject[]
      const categories: Category[] = []
      for (let i = 0; i < rows.length; i++) {
        categories.push(parseMedicalMallCategory(JSON.parse(JSON.stringify(rows[i])) as UTSJSONObject))
      }
      logConsumerQuerySuccess('getMedicalMallSubCategories', 'medical_mall_categories', categories.length)
      return categories
    } catch (error) {
      logConsumerQueryFailure('getMedicalMallSubCategories', 'medical_mall_categories', error)
      return []
    }
  }

  async getMedicalMallCategoryChildrenIds(parentId: string): Promise<string[]> {
    try {
      let response: any
      if (parentId == 'all_medical') {
        response = await supa
          .from('medical_mall_categories')
          .select('id')
          .eq('is_active', true)
          .is('deleted_at', null)
          .eq('level', 2)
          .order('sort_order', { ascending: true })
          .execute()
      } else {
        response = await supa
          .from('medical_mall_categories')
          .select('id')
          .eq('parent_id', parentId)
          .eq('is_active', true)
          .is('deleted_at', null)
          .order('sort_order', { ascending: true })
          .execute()
      }

      if (response.error != null || response.data == null) {
        return []
      }

      const rows = response.data as UTSJSONObject[]
      const ids: string[] = []
      for (let i = 0; i < rows.length; i++) {
        const row = JSON.parse(JSON.stringify(rows[i])) as UTSJSONObject
        const id = safeGetString(row, 'id')
        if (id != '') {
          ids.push(id)
        }
      }
      return ids
    } catch (error) {
      console.error('获取医疗商城子分类 ID 失败:', error)
      return []
    }
  }

  async getMedicalMallProductsByCategory(categoryId: string, page: number = 1, limit: number = 20): Promise<PaginatedResponse<Product>> {
    try {
      if (categoryId == 'recommend') {
        return await this.getMedicalMallSmartRecommendations(page, limit)
      }
      if (!logConsumerQueryStart('getMedicalMallProductsByCategory', 'medical_mall_product_categories', '*')) {
        return emptyProductPage(page, limit)
      }

      const targetCategoryIds: string[] = []
      if (categoryId == 'all_medical') {
        const allChildren = await this.getMedicalMallCategoryChildrenIds('all_medical')
        for (let i = 0; i < allChildren.length; i++) {
          targetCategoryIds.push(allChildren[i])
        }
      } else {
        const categoryResponse = await supa
          .from('medical_mall_categories')
          .select('id, level')
          .eq('id', categoryId)
          .eq('is_active', true)
          .is('deleted_at', null)
          .limit(1)
          .execute()

        targetCategoryIds.push(categoryId)
        if (categoryResponse.error == null && categoryResponse.data != null) {
          const categoryRows = categoryResponse.data as UTSJSONObject[]
          if (categoryRows.length > 0) {
            const categoryObj = JSON.parse(JSON.stringify(categoryRows[0])) as UTSJSONObject
            if (safeGetNumber(categoryObj, 'level') == 1) {
              const childIds = await this.getMedicalMallCategoryChildrenIds(categoryId)
              for (let i = 0; i < childIds.length; i++) {
                if (targetCategoryIds.indexOf(childIds[i]) == -1) {
                  targetCategoryIds.push(childIds[i])
                }
              }
            }
          }
        }
      }

      const linkedIds: string[] = []
      if (targetCategoryIds.length > 0) {
        const linkResponse = await supa
          .from('medical_mall_product_categories')
          .select('product_id, sort_order, created_at')
          .in('category_id', buildAnyStringList(targetCategoryIds))
          .is('deleted_at', null)
          .order('sort_order', { ascending: true })
          .order('created_at', { ascending: false })
          .limit(500)
          .execute()

        if (linkResponse.error == null && linkResponse.data != null) {
          const linkRows = linkResponse.data as UTSJSONObject[]
          for (let i = 0; i < linkRows.length; i++) {
            const row = JSON.parse(JSON.stringify(linkRows[i])) as UTSJSONObject
            const productId = safeGetString(row, 'product_id')
            if (productId != '' && linkedIds.indexOf(productId) == -1) {
              linkedIds.push(productId)
            }
          }
        }
      }

      let finalProducts: Product[] = []
      if (linkedIds.length > 0) {
        const productResponse = await supa
          .from('ml_products_detail_view')
          .select('*')
          .in('id', buildAnyStringList(linkedIds))
          .eq('status', '1')
          .execute()

        if (productResponse.error == null && productResponse.data != null) {
          const rows = productResponse.data as any[]
          const parsed: Product[] = []
          for (let i = 0; i < rows.length; i++) {
            const rowObj = JSON.parse(JSON.stringify(rows[i])) as UTSJSONObject
            if (isRxHiddenProduct(rowObj)) {
              continue
            }
            parsed.push(parseProductFromRaw(rows[i]))
          }
          finalProducts = sortProductsByIdOrder(parsed, linkedIds)
        }
      }

      if (finalProducts.length == 0) {
        const fallbackResponse = await supa
          .from('ml_products_detail_view')
          .select('*')
          .eq('status', '1')
          .order('sale_count', { ascending: false })
          .order('created_at', { ascending: false })
          .limit(300)
          .execute()

        if (fallbackResponse.error == null && fallbackResponse.data != null) {
          const fallbackRows = fallbackResponse.data as any[]
          for (let i = 0; i < fallbackRows.length; i++) {
            const rowObj = JSON.parse(JSON.stringify(fallbackRows[i])) as UTSJSONObject
            if (!matchesMedicalMallFallback(rowObj, categoryId)) {
              continue
            }
            finalProducts.push(parseProductFromRaw(fallbackRows[i]))
          }
        }
      }

      const deduped = dedupeProducts(finalProducts)
      const startIndex = (page - 1) * limit
      const endIndex = startIndex + limit
      return {
        data: deduped.slice(startIndex, endIndex),
        total: deduped.length,
        page,
        limit,
        hasmore: deduped.length > endIndex
      }
    } catch (error) {
      logConsumerQueryFailure('getMedicalMallProductsByCategory', 'medical_mall_product_categories', error)
      console.error('获取医疗商城分类商品失败:', error)
      return emptyProductPage(page, limit)
    }
  }

  async getMedicalMallSmartRecommendations(page: number = 1, limit: number = 10): Promise<PaginatedResponse<Product>> {
    try {
      if (!logConsumerQueryStart('getMedicalMallSmartRecommendations', 'medical_mall_product_categories', '*')) {
        return emptyProductPage(page, limit)
      }

      const linkedIds: string[] = []
      const linkResponse = await supa
        .from('medical_mall_product_categories')
        .select('product_id, is_primary, sort_order, created_at')
        .is('deleted_at', null)
        .order('is_primary', { ascending: false })
        .order('sort_order', { ascending: true })
        .order('created_at', { ascending: false })
        .limit(500)
        .execute()

      if (linkResponse.error == null && linkResponse.data != null) {
        const linkRows = linkResponse.data as UTSJSONObject[]
        for (let i = 0; i < linkRows.length; i++) {
          const row = JSON.parse(JSON.stringify(linkRows[i])) as UTSJSONObject
          const productId = safeGetString(row, 'product_id')
          if (productId != '' && linkedIds.indexOf(productId) == -1) {
            linkedIds.push(productId)
          }
        }
      }

      const merged: Product[] = []
      const addedIds = new Set<string>()

      if (linkedIds.length > 0) {
        const linkedProductResponse = await supa
          .from('ml_products_detail_view')
          .select('*')
          .in('id', buildAnyStringList(linkedIds))
          .eq('status', '1')
          .execute()

        if (linkedProductResponse.error == null && linkedProductResponse.data != null) {
          const rows = linkedProductResponse.data as any[]
          const parsed: Product[] = []
          for (let i = 0; i < rows.length; i++) {
            const rowObj = JSON.parse(JSON.stringify(rows[i])) as UTSJSONObject
            if (isRxHiddenProduct(rowObj)) {
              continue
            }
            parsed.push(parseProductFromRaw(rows[i]))
          }
          const ordered = sortProductsByIdOrder(parsed, linkedIds)
          for (let i = 0; i < ordered.length; i++) {
            if (!addedIds.has(ordered[i].id)) {
              merged.push(ordered[i])
              addedIds.add(ordered[i].id)
            }
          }
        }
      }

      if (merged.length < page * limit + limit) {
        const fallbackResponse = await supa
          .from('ml_products_detail_view')
          .select('*')
          .eq('status', '1')
          .order('sale_count', { ascending: false })
          .order('created_at', { ascending: false })
          .limit(300)
          .execute()

        if (fallbackResponse.error == null && fallbackResponse.data != null) {
          const rows = fallbackResponse.data as any[]
          for (let i = 0; i < rows.length; i++) {
            const rowObj = JSON.parse(JSON.stringify(rows[i])) as UTSJSONObject
            if (!matchesMedicalMallFallback(rowObj, 'recommend')) {
              continue
            }
            const product = parseProductFromRaw(rows[i])
            if (!addedIds.has(product.id)) {
              merged.push(product)
              addedIds.add(product.id)
            }
          }
        }
      }

      const startIndex = (page - 1) * limit
      const endIndex = startIndex + limit
      return {
        data: merged.slice(startIndex, endIndex),
        total: merged.length,
        page,
        limit,
        hasmore: merged.length > endIndex
      }
    } catch (error) {
      logConsumerQueryFailure('getMedicalMallSmartRecommendations', 'medical_mall_product_categories', error)
      console.error('获取医疗商城推荐商品失败:', error)
      return emptyProductPage(page, limit)
    }
  }

  // 根据商品ID获取SKU列表
  async getProductSkus(productId: string): Promise<ProductSku[]> {
    try {
      console.log('[getProductSkus] 开始获取SKU，商品ID:', productId)
      const response = await supa
        .from('ml_product_skus')
        .select('*')
        .eq('product_id', productId)
        .eq('status', '1')
        .execute()
      
      if (response.error != null) {
        console.error('获取商品SKU失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) return []
      
      const skus: ProductSku[] = []
      const rawList = rawData as any[]
      console.log('[getProductSkus] 获取到SKU数量:', rawList.length)
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const skuObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        const rawId = skuObj.get('id')
        const rawSkuCode = skuObj.get('sku_code')
        const rawProdId = skuObj.get('product_id')
        const rawPrice = skuObj.get('price')
        const rawStock = skuObj.get('stock')
        const rawImageUrl = skuObj.get('image_url')
        const rawSpecs = skuObj.get('specifications')
        
        let specsStr = ''
        if (rawSpecs != null) {
          try {
            if (typeof rawSpecs == 'string') {
              specsStr = rawSpecs as string
            } else {
              specsStr = JSON.stringify(rawSpecs)
            }
          } catch(e) {
            console.error('解析SKU规格失败', e)
          }
        }
        
        const sku: ProductSku = {
          id: (typeof rawId == 'string') ? (rawId as string) : '',
          product_id: (typeof rawProdId == 'string') ? (rawProdId as string) : '',
          sku_code: (typeof rawSkuCode == 'string') ? (rawSkuCode as string) : '',
          specifications: specsStr,
          price: (typeof rawPrice == 'number') ? (rawPrice as number) : 0,
          stock: (typeof rawStock == 'number') ? (rawStock as number) : 0,
          image_url: (typeof rawImageUrl == 'string') ? (rawImageUrl as string) : '',
          status: 1
        }
        skus.push(sku)
      }
      return skus
    } catch (error) {
      console.error('获取商品SKU异常:', error)
      return []
    }
  }

  // 搜索商品
  async searchProducts(
    keyword: string, 
    page: number = 1, 
    limit: number = 20,
    sortBy: string = 'sales',
    ascending: boolean = false
  ): Promise<PaginatedResponse<Product>> {
    try {
      const keywordLower = keyword.toLowerCase()
      const encodedKeyword = encodeURIComponent(keywordLower)
      const orString = `name.ilike.%${encodedKeyword}%,description.ilike.%${encodedKeyword}%,subtitle.ilike.%${encodedKeyword}%,brand_name.ilike.%${encodedKeyword}%`
      console.log('[searchProducts] 搜索关键词:', keyword, '编码后:', encodedKeyword)
      console.log('[searchProducts] or条件:', orString)
      
      let query = supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('status', 1)
        .or(orString)
      
      if (sortBy === 'price') {
        query = query.order('base_price', { ascending })
      } else if (sortBy === 'sales' || sortBy === 'sale_count') {
        query = query.order('sale_count', { ascending: false })
      } else {
        query = query.order('sale_count', { ascending: false })
      }
      
      const response = await query
        .page(page)
        .limit(limit)
        .execute()
      
      let dataLength = 0
      try {
        const respData = response.data
        if (respData != null && Array.isArray(respData)) {
          dataLength = (respData as any[]).length
        }
      } catch (e) {
        console.error('[searchProducts] 获取数据长度失败:', e)
      }
      let statusNum = 0
      try {
        statusNum = response.status as number
      } catch (e) {}
      console.log('[searchProducts] 响应状态:', statusNum, '数据条数:', dataLength)
      
      let hasError = false
      try {
        hasError = response.error != null
      } catch (e) {}
      if (hasError) {
        console.error('[searchProducts] 搜索商品失败:', response.error)
        return {
          data: [] as Product[],
          total: 0,
          page,
          limit,
          hasmore: false
        }
      }
      
      const rawData = response.data
      console.log('[searchProducts] rawData:', rawData != null ? 'not null' : 'null')
      if (rawData == null) {
        return {
          data: [] as Product[],
          total: 0,
          page,
          limit,
          hasmore: false
        }
      }
      
      const products: Product[] = []
      let rawList: any[] = []
      try {
        rawList = rawData as any[]
        console.log('[searchProducts] rawList长度:', rawList.length)
      } catch (e) {
        console.error('[searchProducts] 转换rawList失败:', e)
        return {
          data: [] as Product[],
          total: 0,
          page,
          limit,
          hasmore: false
        }
      }
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        console.log('[searchProducts] 处理第', i + 1, '个商品')
        products.push(parseProductFromRaw(item))
      }
      
      let totalNum = 0
      try {
        totalNum = response.total as number
      } catch (e) {}
      let hasmoreVal = false
      try {
        hasmoreVal = response.hasmore as boolean
      } catch (e) {}
      
      return {
        data: products,
        total: totalNum > 0 ? totalNum : products.length,
        page,
        limit,
        hasmore: hasmoreVal
      }
    } catch (error) {
      console.error('搜索商品异常:', error)
      return {
        data: [] as Product[],
        total: 0,
        page,
        limit,
        hasmore: false
      }
    }
  }

  // 搜索店铺
  async searchShops(
    keyword: string,
    page: number = 1,
    limit: number = 20
  ): Promise<PaginatedResponse<Shop>> {
    try {
      const encodedKeyword = encodeURIComponent(keyword)
      const response = await supa
        .from('ml_shops')
        .select('*', { count: 'exact' })
        .ilike('shop_name', `%${encodedKeyword}%`)
        .order('product_count', { ascending: false })
        .page(page)
        .limit(limit)
        .execute()

      if (response.error != null) {
        console.error('搜索店铺失败:', response.error)
        return { data: [] as Shop[], total: 0, page, limit, hasmore: false }
      }

      const rawData = response.data
      if (rawData == null) {
        return { data: [] as Shop[], total: 0, page, limit, hasmore: false }
      }

      const shops: Shop[] = []
      const dataList = rawData as any[]
      for (let i = 0; i < dataList.length; i++) {
        const item = dataList[i]
        const shopObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        // 手动过滤 status
        const rawStatus = shopObj.get('status')
        let statusNum: number = 0
        if (typeof rawStatus == 'number') {
          statusNum = rawStatus as number
        }
        if (statusNum !== 1) continue
        
        // 手动创建 Shop 对象，避免安卓端类型转换错误
        const shop: Shop = {
          id: shopObj.getString('id') ?? '',
          merchant_id: shopObj.getString('merchant_id') ?? '',
          shop_name: shopObj.getString('shop_name') ?? '',
          shop_logo: shopObj.getString('shop_logo'),
          shop_banner: shopObj.getString('shop_banner'),
          description: shopObj.getString('description'),
          contact_name: shopObj.getString('contact_name'),
          contact_phone: shopObj.getString('contact_phone'),
          rating_avg: shopObj.getNumber('rating_avg'),
          total_sales: shopObj.getNumber('total_sales'),
          product_count: shopObj.getNumber('product_count'),
          total_sales_count: shopObj.getNumber('total_sales_count'),
          created_at: shopObj.getString('created_at')
        }
        shops.push(shop)
      }

      return {
        data: shops,
        total: response.total ?? shops.length,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
       console.error('搜索店铺异常:', error)
       return { data: [] as Shop[], total: 0, page, limit, hasmore: false }
    }
  }

  // 获取单个商品详情
  async getProductById(productId: string): Promise<Product | null> {
    try {
      console.log('[getProductById] 开始获取商品详情，ID:', productId)
      const response = await supa
        .from('ml_products_detail_view')
        .select('*')
        .eq('id', productId)
        .limit(1)
        .execute()
      
      if (response.error != null) {
        console.error('获取商品详情失败:', response.error)
        return null
      }
      
      const rawData = response.data
      if (rawData == null) {
        console.log('[getProductById] 数据为空')
        return null
      }
      
      const rawList = rawData as any[]
      if (rawList.length == 0) {
        console.log('[getProductById] 未找到商品')
        return null
      }
      
      const item = rawList[0]
      const product = parseProductFromRaw(item)
      console.log('[getProductById] 成功获取商品:', product.name)
      return product
    } catch (error) {
      console.error('获取商品详情异常:', error)
      return null
    }
  }

  // --- 关注店铺相关 ---

  // 检查是否已关注店铺
  async isShopFollowed(shopId: string, userId: string): Promise<boolean> {
      try {
          const res = await supa
            .from('ml_shop_follows')
            .select('id', { count: 'exact' })
            .eq('shop_id', shopId)
            .eq('user_id', userId)
            .limit(1)
            .execute()
          
          return (res.total != null && res.total! > 0)
      } catch (e) {
          console.error('Check follow error:', e)
          return false
      }
  }

  // 关注店铺
  async followShop(shopId: string, userId: string): Promise<boolean> {
      try {
          const res = await supa
            .from('ml_shop_follows')
            .insert({
                user_id: userId,
                shop_id: shopId
            })
            .execute()
          
          return res.error == null
      } catch (e) {
          console.error('Follow shop error:', e)
          return false
      }
  }

  // 取消关注
  async unfollowShop(shopId: string, userId: string): Promise<boolean> {
      try {
          const res = await supa
            .from('ml_shop_follows')
            .eq('shop_id', shopId)
            .eq('user_id', userId)
            .delete()
            .execute()
            
          return res.error == null
      } catch (e) {
          console.error('Unfollow shop error:', e)
          return false
      }
  }

  // 获取我关注的店铺列表
  async getFollowedShops(userId: string): Promise<any[]> {
      try {
          // 关联查询店铺信息
          const res = await supa
             .from('ml_shop_follows')
             .select('*, ml_shops(*)') 
             .eq('user_id', userId)
             .order('created_at', { ascending: false })
             .execute()
             
          if (res.error != null) {
              console.error('getFollowedShops error:', res.error)
              return []
          }
          
          return res.data as any[]
      } catch (e) {
          console.error('getFollowedShops exception:', e)
          return []
      }
  }

  // 根据商户ID获取店铺信息
  async getShopByMerchantId(merchantId: string): Promise<Shop | null> {
    try {
      console.log('[getShopByMerchantId] 开始获取店铺信息，merchantId:', merchantId)
      // 1. Try querying by merchant_id
      let response = await supa
        .from('ml_shops')
        .select('*')
        .eq('merchant_id', merchantId)
        .limit(1)
        .execute()
        
      if (response.error == null && response.data != null && (response.data as any[]).length > 0) {
         const shopData = (response.data as any[])[0]
         const shop = this.parseShopFromRaw(shopData)
         console.log('[getShopByMerchantId] 通过 merchant_id 找到店铺:', shop.shop_name)
         return shop
      }

      // 2. Fallback: Try querying by id (Maybe the passed ID is the Shop ID?)
      console.log('getShopByMerchantId: merchant_id not found, trying id...', merchantId)
      response = await supa
        .from('ml_shops')
        .select('*')
        .eq('id', merchantId)
        .limit(1)
        .execute()

      if (response.error == null && response.data != null && (response.data as any[]).length > 0) {
         console.log('Found shop by ID instead of MerchantID')
         const shopData = (response.data as any[])[0]
         const shop = this.parseShopFromRaw(shopData)
         return shop
      }

      if (response.error != null) {
        console.error('获取店铺信息失败:', response.error)
      }
      return null
    } catch (error) {
      console.error('获取店铺信息异常:', error)
      return null
    }
  }
  
  // 解析店铺数据
  parseShopFromRaw(item: any): Shop {
    const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
    
    const getSafeString = (key: string): string => {
      const val = itemObj.get(key)
      if (val == null) return ''
      if (typeof val == 'string') return val
      return ''
    }
    
    const getSafeNumber = (key: string): number => {
      const val = itemObj.get(key)
      if (val == null) return 0
      if (typeof val == 'number') return val
      return 0
    }
    
    return {
      id: getSafeString('id'),
      merchant_id: getSafeString('merchant_id'),
      shop_name: getSafeString('shop_name'),
      shop_logo: getSafeString('shop_logo'),
      shop_banner: getSafeString('shop_banner'),
      description: getSafeString('description'),
      contact_name: getSafeString('contact_name'),
      contact_phone: getSafeString('contact_phone'),
      rating_avg: getSafeNumber('rating_avg'),
      total_sales: getSafeNumber('total_sales'),
      product_count: getSafeNumber('product_count'),
      total_sales_count: getSafeNumber('total_sales_count'),
      created_at: getSafeString('created_at')
    } as Shop
  }

  // 根据商户ID获取商品列表
  async getProductsByMerchantId(merchantId: string, page: number = 1, limit: number = 20): Promise<PaginatedResponse<Product>> {
    try {
      console.log('getProductsByMerchantId querying for:', merchantId)
      
      // 1. Try fetching from view strictly first
      let query = supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('merchant_id', merchantId)
        // .eq('status', 1) // Temporarily disabled status check to see if products exist at all
        .order('created_at', { ascending: false })
        .page(page)
        .limit(limit)
      
      const response = await query.execute()
      
      // 检查视图结果：如果有错误 OR 数据为空，都尝试去查原始表
      if (response.error != null || (response.data != null && (response.data as any[]).length === 0)) {
        if (response.error != null) {
            console.error('获取商户商品失败 (View):', response.error)
        } else {
            console.log('View returned 0 products, trying raw table fallback...')
        }
        
        // Fallback: Try raw table
        console.log('Falling back to raw ml_products table...')
        const query2 = supa
            .from('ml_products')
            .select('*', { count: 'exact' })
            .eq('merchant_id', merchantId)
            // .eq('status', 1) // Also disabled here
            .order('created_at', { ascending: false })
            .page(page)
            .limit(limit)
         
        const res2 = await query2.execute()
        if (res2.error != null) {
             console.error('获取商户商品失败 (Raw):', res2.error)
             return {data:[] as Product[], total:0, page, limit, hasmore:false}
        }
        
        console.log(`Fallback (Raw) found: ${(res2.data as any[]).length} products`)
        
        const mappedData: Product[] = []
        const rawData = res2.data as any[]
        for(let i = 0; i < rawData.length; i++) {
            const item = JSON.parse(JSON.stringify(rawData[i])) as UTSJSONObject
            const images: string[] = []
            
            const mainImageUrl = fixImageUrl(item.getString('main_image_url'))
            if (mainImageUrl != null && mainImageUrl !== '') {
                images.push(mainImageUrl)
            }

            const imageUrlsRaw = item.get('image_urls')
            if (imageUrlsRaw != null) {
                try {
                    if (Array.isArray(imageUrlsRaw)) {
                        const arr = imageUrlsRaw as string[]
                        if (arr.length > 0 && images.length === 0) {
                            for (let j = 0; j < arr.length; j++) {
                                const fixedUrl = fixImageUrl(arr[j])
                                if (fixedUrl !== '') images.push(fixedUrl)
                            }
                        }
                    } else {
                        const rawUrlStr = imageUrlsRaw as string
                        if (rawUrlStr.startsWith('[')) {
                            const parsed = JSON.parse(rawUrlStr)
                            if (Array.isArray(parsed) && images.length === 0) {
                                for (let j = 0; j < parsed.length; j++) {
                                    const fixedUrl = fixImageUrl(parsed[j] as string)
                                    if (fixedUrl !== '') images.push(fixedUrl)
                                }
                            }
                        } else {
                            const fixedUrl = fixImageUrl(rawUrlStr)
                            if (fixedUrl !== '' && images.indexOf(fixedUrl) === -1) images.push(fixedUrl)
                        }
                    }
                } catch(e) {
                    console.error('解析图片数组失败:', e)
                }
            }
            
            if (images.length === 0) {
                images.push('/static/default-product.png')
            }
            
            let safePrice = item.getNumber('base_price')
            if (safePrice == null) {
                const p = item.getNumber('price')
                safePrice = p != null ? p : 0
            }
            
            let safeOriginalPrice = item.getNumber('market_price')
            if (safeOriginalPrice == null) {
                const op = item.getNumber('original_price')
                safeOriginalPrice = op != null ? op : safePrice
            }
            
            let safeStock = item.getNumber('total_stock')
            if (safeStock == null) {
                let as_ = item.getNumber('available_stock')
                if (as_ == null) {
                    const s = item.getNumber('stock')
                    safeStock = s != null ? s : 0
                } else {
                    safeStock = as_
                }
            }
            
            let safeSales = item.getNumber('sale_count')
            if (safeSales == null) {
                const s = item.getNumber('sales')
                safeSales = s != null ? s : 0
            }
            
            const product: Product = {
                id: item.getString('id') ?? '',
                category_id: item.getString('category_id') ?? '',
                merchant_id: item.getString('merchant_id') ?? '',
                name: item.getString('name') ?? '',
                description: item.getString('description') ?? '',
                images: images,
                price: safePrice,
                original_price: safeOriginalPrice,
                stock: safeStock,
                sales: safeSales,
                status: item.getNumber('status') ?? 1,
                created_at: item.getString('created_at') ?? '',
                base_price: safePrice,
                market_price: safeOriginalPrice,
                main_image_url: images.length > 0 ? images[0] : '',
                sale_count: safeSales,
                total_stock: safeStock
            } as Product
            mappedData.push(product)
        }

        return {
            data: mappedData,
            total: res2.total ?? 0,
            page,
            limit,
            hasmore: res2.hasmore ?? false
        }
      }
      
      console.log(`Merchant products found: ${(response.data as any[]).length}`)
      
      const viewData = response.data as any[]
      const parsedProducts: Product[] = []
      for (let i = 0; i < viewData.length; i++) {
          parsedProducts.push(parseProductFromRaw(viewData[i]))
      }
      
      return {
        data: parsedProducts,
        total: response.total ?? 0,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
      console.error('获取商户商品异常:', error)
      return {
        data: [] as Product[],
        total: 0,
        page,
        limit,
        hasmore: false
      }
    }
  }

  // 根据店铺ID获取商品列表（新增）
  async getProductsByShopId(shopId: string, page: number = 1, limit: number = 20): Promise<PaginatedResponse<Product>> {
    try {
      console.log('getProductsByShopId querying for:', shopId)
      
      // 1. Try fetching from view with shop_id
      let query = supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('shop_id', shopId)
        .order('created_at', { ascending: false })
        .page(page)
        .limit(limit)
      
      const response = await query.execute()
      
      // 检查视图结果：如果有错误 OR 数据为空，都尝试去查原始表
      if (response.error != null || (response.data != null && (response.data as any[]).length === 0)) {
        if (response.error != null) {
            console.error('获取店铺商品失败 (View):', response.error)
        } else {
            console.log('View returned 0 products, trying raw table fallback...')
        }
        
        // Fallback: Try raw table with shop_id
        console.log('Falling back to raw ml_products table with shop_id...')
        const query2 = supa
            .from('ml_products')
            .select('*', { count: 'exact' })
            .eq('shop_id', shopId)
            .order('created_at', { ascending: false })
            .page(page)
            .limit(limit)
         
        const res2 = await query2.execute()
        if (res2.error != null) {
             console.error('获取店铺商品失败 (Raw):', res2.error)
             return {data:[] as Product[], total:0, page, limit, hasmore:false}
        }
        
        console.log(`Fallback (Raw) found: ${(res2.data as any[]).length} products`)
        
        const mappedData: Product[] = []
        const rawData = res2.data as any[]
        for(let i = 0; i < rawData.length; i++) {
            const item = JSON.parse(JSON.stringify(rawData[i])) as UTSJSONObject
            const images: string[] = []
            
            const mainImageUrl = fixImageUrl(item.getString('main_image_url'))
            if (mainImageUrl != null && mainImageUrl !== '') {
                images.push(mainImageUrl)
            }

            const imageUrlsRaw = item.get('image_urls')
            if (imageUrlsRaw != null) {
                try {
                    if (Array.isArray(imageUrlsRaw)) {
                        const arr = imageUrlsRaw as string[]
                        if (arr.length > 0 && images.length === 0) {
                            for (let j = 0; j < arr.length; j++) {
                                const fixedUrl = fixImageUrl(arr[j])
                                if (fixedUrl !== '') images.push(fixedUrl)
                            }
                        }
                    } else {
                        const rawUrlStr = imageUrlsRaw as string
                        if (rawUrlStr.startsWith('[')) {
                            const parsed = JSON.parse(rawUrlStr)
                            if (Array.isArray(parsed) && images.length === 0) {
                                for (let j = 0; j < parsed.length; j++) {
                                    const fixedUrl = fixImageUrl(parsed[j] as string)
                                    if (fixedUrl !== '') images.push(fixedUrl)
                                }
                            }
                        } else {
                            const fixedUrl = fixImageUrl(rawUrlStr)
                            if (fixedUrl !== '' && images.indexOf(fixedUrl) === -1) images.push(fixedUrl)
                        }
                    }
                } catch(e) {
                    console.error('解析图片数组失败:', e)
                }
            }
            
            if (images.length === 0) {
                images.push('/static/default-product.png')
            }
            
            let safePrice = item.getNumber('base_price')
            if (safePrice == null) {
                const p = item.getNumber('price')
                safePrice = p != null ? p : 0
            }
            
            let safeOriginalPrice = item.getNumber('market_price')
            if (safeOriginalPrice == null) {
                const op = item.getNumber('original_price')
                safeOriginalPrice = op != null ? op : safePrice
            }
            
            let safeStock = item.getNumber('total_stock')
            if (safeStock == null) {
                let as_ = item.getNumber('available_stock')
                if (as_ == null) {
                    const s = item.getNumber('stock')
                    safeStock = s != null ? s : 0
                } else {
                    safeStock = as_
                }
            }
            
            let safeSales = item.getNumber('sale_count')
            if (safeSales == null) {
                const s = item.getNumber('sales')
                safeSales = s != null ? s : 0
            }
            
            const product: Product = {
                id: item.getString('id') ?? '',
                category_id: item.getString('category_id') ?? '',
                merchant_id: item.getString('merchant_id') ?? '',
                name: item.getString('name') ?? '',
                description: item.getString('description') ?? '',
                images: images,
                price: safePrice,
                original_price: safeOriginalPrice,
                stock: safeStock,
                sales: safeSales,
                status: item.getNumber('status') ?? 1,
                created_at: item.getString('created_at') ?? '',
                base_price: safePrice,
                market_price: safeOriginalPrice,
                main_image_url: images.length > 0 ? images[0] : '',
                sale_count: safeSales,
                total_stock: safeStock
            } as Product
            mappedData.push(product)
        }

        return {
            data: mappedData,
            total: res2.total ?? 0,
            page,
            limit,
            hasmore: res2.hasmore ?? false
        }
      }
      
      console.log(`Shop products found: ${(response.data as any[]).length}`)
      
      const viewData = response.data as any[]
      const parsedProducts: Product[] = []
      for (let i = 0; i < viewData.length; i++) {
          parsedProducts.push(parseProductFromRaw(viewData[i]))
      }
      
      return {
        data: parsedProducts,
        total: response.total ?? 0,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
      console.error('获取店铺商品异常:', error)
      return {
        data: [] as Product[],
        total: 0,
        page,
        limit,
        hasmore: false
      }
    }
  }

  // 获取热销商品（按销量排序）
  async getHotProducts(limit: number = 10): Promise<Product[]> {
    try {
      console.log('[getHotProducts] 开始获取热销商品...')
      
      // 在数据库层面过滤 status，获取更多数据以便手动过滤 is_hot
      const response = await supa
        .from('ml_products_detail_view')
        .select('*')
        .eq('status', '1')  // 使用字符串 '1'
        .order('sale_count', { ascending: false })
        .limit(limit * 5)  // 获取更多数据以便过滤
        .execute()
      
      if (response.error != null) {
        console.error('获取热销商品失败:', response.error)
        return []
      }
      
      const rawData = response.data
      console.log('[getHotProducts] 原始数据条数:', rawData != null ? (rawData as any[]).length : 0)
      if (rawData == null) {
        console.log('[getHotProducts] 数据为空')
        return []
      }
      
      const products: Product[] = []
      const rawList = rawData as any[]
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const prodObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        // 手动过滤 is_hot
        const rawIsHot = prodObj.get('is_hot')
        let isHotBool: boolean = false
        if (typeof rawIsHot == 'boolean') {
          isHotBool = rawIsHot as boolean
        } else if (typeof rawIsHot == 'number') {
          isHotBool = (rawIsHot as number) == 1
        }
        if (!isHotBool) continue
        
        products.push(parseProductFromRaw(item))
        
        // 达到目标数量就停止
        if (products.length >= limit) break
      }
      console.log('[getHotProducts] 最终返回商品数:', products.length)
      return products
    } catch (error) {
      console.error('获取热销商品异常:', error)
      return []
    }
  }

  // 获取按销量排序的商品（所有商品，不限制 is_hot）
  async getProductsBySales(page: number = 1, limit: number = 10): Promise<PaginatedResponse<Product>> {
    try {
      if (!logConsumerQueryStart('getProductsBySales', 'ml_products_detail_view', '*')) {
        return emptyProductPage(page, limit)
      }
      console.log('[getProductsBySales] 开始获取销量排序商品...')
      const response = await supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('status', '1')
        .order('sale_count', { ascending: false })
        .page(page)
        .limit(limit)
        .execute()
      
      if (response.error != null) {
        logConsumerQueryFailure('getProductsBySales', 'ml_products_detail_view', response.error)
        console.error('获取销量排序商品失败:', response.error)
        return emptyProductPage(page, limit)
      }
      
      const rawData = response.data
      if (rawData == null) {
        return emptyProductPage(page, limit)
      }
      
      const products: Product[] = []
      const rawList = rawData as any[]
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        products.push(parseProductFromRaw(item))
      }
      console.log('[getProductsBySales] 返回商品数:', products.length)
      logConsumerQuerySuccess('getProductsBySales', 'ml_products_detail_view', products.length)
      return {
        data: products,
        total: response.total ?? products.length,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
      logConsumerQueryFailure('getProductsBySales', 'ml_products_detail_view', error)
      console.error('获取销量排序商品异常:', error)
      return emptyProductPage(page, limit)
    }
  }

  // 获取按价格排序的商品（升序：从低到高）
  async getProductsByPrice(page: number = 1, limit: number = 10, ascending: boolean = true): Promise<PaginatedResponse<Product>> {
    try {
      if (!logConsumerQueryStart('getProductsByPrice', 'ml_products_detail_view', '*')) {
        return emptyProductPage(page, limit)
      }
      const response = await supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('status', '1')  // 在数据库层面过滤
        .order('base_price', { ascending })
        .page(page)
        .limit(limit)
        .execute()
      
      if (response.error != null) {
        logConsumerQueryFailure('getProductsByPrice', 'ml_products_detail_view', response.error)
        console.error('获取价格排序商品失败:', response.error)
        return emptyProductPage(page, limit)
      }
      
      const rawData = response.data
      if (rawData == null) {
        return emptyProductPage(page, limit)
      }
      
      const products: Product[] = []
      const rawList = rawData as any[]
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        products.push(parseProductFromRaw(item))
      }
      logConsumerQuerySuccess('getProductsByPrice', 'ml_products_detail_view', products.length)
      return {
        data: products,
        total: response.total ?? products.length,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
      logConsumerQueryFailure('getProductsByPrice', 'ml_products_detail_view', error)
      console.error('获取价格排序商品异常:', error)
      return emptyProductPage(page, limit)
    }
  }

  // 获取新品（按创建时间排序，最新的在前）
  async getProductsByNewest(page: number = 1, limit: number = 10): Promise<PaginatedResponse<Product>> {
    try {
      if (!logConsumerQueryStart('getProductsByNewest', 'ml_products_detail_view', '*')) {
        return emptyProductPage(page, limit)
      }
      console.log('[getProductsByNewest] 开始获取新品...')
      const response = await supa
        .from('ml_products_detail_view')
        .select('*', { count: 'exact' })
        .eq('status', '1')
        .order('is_new', { ascending: false })
        .order('created_at', { ascending: false })
        .page(page)
        .limit(limit)
        .execute()
      
      if (response.error != null) {
        logConsumerQueryFailure('getProductsByNewest', 'ml_products_detail_view', response.error)
        console.error('获取新品失败:', response.error)
        return emptyProductPage(page, limit)
      }
      
      const rawData = response.data
      if (rawData == null) {
        return emptyProductPage(page, limit)
      }
      
      const products: Product[] = []
      const rawList = rawData as any[]
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        products.push(parseProductFromRaw(item))
      }
      
      console.log('[getProductsByNewest] 返回商品数:', products.length)
      logConsumerQuerySuccess('getProductsByNewest', 'ml_products_detail_view', products.length)
      return {
        data: products,
        total: response.total ?? products.length,
        page,
        limit,
        hasmore: response.hasmore ?? false
      }
    } catch (error) {
      logConsumerQueryFailure('getProductsByNewest', 'ml_products_detail_view', error)
      console.error('获取新品异常:', error)
      return emptyProductPage(page, limit)
    }
  }

  // 获取推荐商品（is_featured=true）
  async getRecommendedProducts(limit: number = 10): Promise<Product[]> {
    try {
      if (!logConsumerQueryStart('getRecommendedProducts', 'ml_products_detail_view', 'id, name, description, base_price, market_price, main_image_url, image_urls, category_id, brand_id, merchant_id, total_stock, sale_count, status, is_featured, is_new, is_hot')) {
        return []
      }
      console.log('[getRecommendedProducts] 开始获取推荐商品...')
      const response = await supa
        .from('ml_products_detail_view')
        .select('id, name, description, base_price, market_price, main_image_url, image_urls, category_id, brand_id, merchant_id, total_stock, sale_count, status, is_featured, is_new, is_hot')
        .eq('status', '1')  // 在数据库层面过滤
        .order('sale_count', { ascending: false })
        .limit(limit * 5)  // 获取更多数据以便过滤 is_featured
        .execute()
      
      console.log('[getRecommendedProducts] 查询完成')
      
      if (response.error != null) {
        logConsumerQueryFailure('getRecommendedProducts', 'ml_products_detail_view', response.error)
        console.error('获取推荐商品失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) {
        console.log('[getRecommendedProducts] 数据为空')
        return []
      }
      
      const products: Product[] = []
      const rawList = rawData as any[]
      console.log('[getRecommendedProducts] 数据条数:', rawList.length)
      
      for (let i: number = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const prodObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        const rawFeatured = prodObj.get('is_featured')
        
        let isFeaturedBool: boolean = false
        if (typeof rawFeatured == 'boolean') {
          isFeaturedBool = rawFeatured as boolean
        } else if (typeof rawFeatured == 'number') {
          isFeaturedBool = (rawFeatured as number) == 1
        }
        if (!isFeaturedBool) {
          continue
        }
        
        products.push(parseProductFromRaw(item))
        if (products.length >= limit) break
      }
      logConsumerQuerySuccess('getRecommendedProducts', 'ml_products_detail_view', products.length)
      return products
    } catch (error) {
      logConsumerQueryFailure('getRecommendedProducts', 'ml_products_detail_view', error)
      console.error('获取推荐商品异常:', error)
      return []
    }
  }

  async getRecommendProducts(params: UTSJSONObject): Promise<Array<UTSJSONObject>> {
    try {
      const categoryId = params.getString('categoryId') ?? ''
      const limitRaw = params.getNumber('limit')
      const offsetRaw = params.getNumber('offset')
      const limit = limitRaw != null && limitRaw > 0 ? limitRaw : 8
      const offset = offsetRaw != null && offsetRaw >= 0 ? offsetRaw : 0
      const excludeProductIdsRaw = params.get('excludeProductIds')
      const excludeProductIds: Array<string> = []

      if (excludeProductIdsRaw != null) {
        const normalized = JSON.parse(JSON.stringify(excludeProductIdsRaw))
        if (Array.isArray(normalized)) {
          for (let i = 0; i < normalized.length; i++) {
            const item = normalized[i]
            if (item != null) {
              const itemText = '' + item
              if (itemText !== '') {
                excludeProductIds.push(itemText)
              }
            }
          }
        }
      }

      const collected: Array<UTSJSONObject> = []
      const collectedIds: Array<string> = []
      const targetCount = offset + limit
      const fetchLimit = limit > 20 ? limit : 20

      const appendRows = (rows: any[]): void => {
        for (let i = 0; i < rows.length; i++) {
          const product = parseProductFromRaw(rows[i])
          const productId = product.id ?? ''
          if (productId === '') {
            continue
          }
          if (excludeProductIds.indexOf(productId) >= 0) {
            continue
          }
          if (collectedIds.indexOf(productId) >= 0) {
            continue
          }
          collectedIds.push(productId)
          collected.push(JSON.parse(JSON.stringify(product)) as UTSJSONObject)
        }
      }

      const fetchBatch = async (preferCategory: boolean): Promise<boolean> => {
        let page = 1
        while (collected.length < targetCount && page <= 10) {
          let rows: any[] = []
          if (preferCategory && categoryId !== '') {
            const response = await this.getProductsByCategory(categoryId, page, fetchLimit)
            rows = response.data as any[]
          } else {
            const response = await this.getProductsBySales(page, fetchLimit)
            rows = response.data as any[]
          }

          if (rows == null) {
            return true
          }
          if (rows.length === 0) {
            return true
          }

          appendRows(rows)

          if (rows.length < fetchLimit) {
            return true
          }
          page += 1
        }
        return true
      }

      if (categoryId !== '') {
        await fetchBatch(true)
      }
      if (collected.length < targetCount) {
        await fetchBatch(false)
      }

      const result: Array<UTSJSONObject> = []
      const end = collected.length < targetCount ? collected.length : targetCount
      for (let i = offset; i < end; i++) {
        result.push(collected[i])
      }
      return result
    } catch (error) {
      console.error('获取通用推荐商品异常:', error)
      return []
    }
  }

  // 获取特价商品（这里假设没有specific flag, just use logic or tag if exists, defaulting to hot for now or just skip）
  // Modify to use compatible logic if badge column doesn't exist
  async getDiscountProducts(limit: number = 10): Promise<Product[]> {
      if (!logConsumerQueryStart('getDiscountProducts', 'ml_products_detail_view', '(none)')) {
       return [] as Product[]
      }
      logConsumerQuerySuccess('getDiscountProducts', 'ml_products_detail_view', 0)
     return [] as Product[] // 暂无特价字段
  }

  // 获取当前用户的购物车商品（关联商品和店铺信息）
  async getCartItems(): Promise<CartItem[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.warn('用户未登录，无法获取购物车')
        return []
      }

      // 查询购物车表，并关联商品表（使用内联关联）
      // 注意：使用 !inner 进行内连接，或者 left join (默认)
      // 修改查询语法以符合 PostgREST 规范
      // 尝试简化查询，先只查购物车，再查商品，避免复杂的嵌套查询导致 400 错误
      const response = await supa
        .from('ml_shopping_cart')
        .select('*')
        .eq('user_id', userId)
        .order('created_at', { ascending: false })
        .execute()
      
      if (response.error != null) {
        console.error('获取购物车失败:', response.error)
        return []
      }
      
      const cartData = response.data as any[]
      // console.log('Raw Cart Data:', JSON.stringify(cartData))
      
      if (cartData == null || cartData.length === 0) {
          return []
      }

      // 收集所有 product_id 和 sku_id
      const productIds: string[] = []
      const skuIds: string[] = []
      for (let i = 0; i < cartData.length; i++) {
          let item = cartData[i]
          let pid: string = ''
          let sid: string = ''
          if (item instanceof UTSJSONObject) {
              pid = item.getString('product_id') ?? ''
              sid = item.getString('sku_id') ?? ''
          } else {
              const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
              pid = itemObj.getString('product_id') ?? ''
              sid = itemObj.getString('sku_id') ?? ''
          }
          if (pid !== '' && !productIds.includes(pid)) {
              productIds.push(pid)
          }
           if (sid !== '' && !skuIds.includes(sid)) {
              skuIds.push(sid)
          }
      }

      // 批量查询商品详情 (使用视图关联店铺信息，修复字段名 specification -> attributes)
      const productMap = new Map<string, any>()
      
      if (productIds.length > 0) {
          // Convert string array to any array for .in()
          const productIdsAny: any[] = []
          for(let i=0; i<productIds.length; i++) {
            productIdsAny.push(productIds[i])
          }

          const productRes = await supa
            .from('ml_products')
            .select('*')
            .in('id', productIdsAny)
            .execute()
            
          console.log('[getCartItems] 商品查询结果:', productRes.error != null ? 'error' : 'success', productRes.error)
          if (productRes.error == null && productRes.data != null) {
              const products = productRes.data as any[]
              console.log('[getCartItems] 商品数量:', products.length)
              for (let i = 0; i < products.length; i++) {
                  let p = products[i]
                  let pid: string = ''
                  let pname: string = ''
                  
                  if (p instanceof UTSJSONObject) {
                      pid = p.getString('id') ?? ''
                      pname = p.getString('name') ?? ''
                  } else {
                      const pObj = JSON.parse(JSON.stringify(p)) as UTSJSONObject
                      pid = pObj.getString('id') ?? ''
                      pname = pObj.getString('name') ?? ''
                  }
                  
                  console.log('[getCartItems] 商品:', pid, pname)
                  
                  if (pid !== '') {
                      productMap.set(pid, p)
                  }
              }
          }
      }

      // 批量查询店铺信息
      const shopMap = new Map<string, string>()
      const merchantIds: string[] = []
      // 遍历 productMap 获取 merchant_id
      productMap.forEach((p: any, pid: string) => {
          let mid: string = ''
          if (p instanceof UTSJSONObject) {
              mid = p.getString('merchant_id') ?? ''
          } else {
              const pObj = JSON.parse(JSON.stringify(p)) as UTSJSONObject
              mid = pObj.getString('merchant_id') ?? ''
          }
          if (mid !== '' && !merchantIds.includes(mid)) {
              merchantIds.push(mid)
          }
      })
      
      if (merchantIds.length > 0) {
          const merchantIdsAny: any[] = []
          for(let i=0; i<merchantIds.length; i++) {
              merchantIdsAny.push(merchantIds[i])
          }
          const shopRes = await supa
            .from('ml_shops')
            .select('merchant_id,shop_name')
            .in('merchant_id', merchantIdsAny)
            .execute()
            
          if (shopRes.error == null && shopRes.data != null) {
              const shops = shopRes.data as any[]
              for (let i = 0; i < shops.length; i++) {
                  let s = shops[i]
                  let mid: string = ''
                  let sname: string = ''
                  if (s instanceof UTSJSONObject) {
                      mid = s.getString('merchant_id') ?? ''
                      sname = s.getString('shop_name') ?? ''
                  } else {
                      const sObj = JSON.parse(JSON.stringify(s)) as UTSJSONObject
                      mid = sObj.getString('merchant_id') ?? ''
                      sname = sObj.getString('shop_name') ?? ''
                  }
                  if (mid !== '') {
                      shopMap.set(mid, sname)
                  }
              }
          }
      }

      // 批量查询 SKU 详情
      const skuMap = new Map<string, any>()
      if (skuIds.length > 0) {
          const skuIdsAny: any[] = []
          for(let i=0; i<skuIds.length; i++) {
              skuIdsAny.push(skuIds[i])
          }
          const skuRes = await supa
            .from('ml_product_skus')
            .select('*')
            .in('id', skuIdsAny)
            .execute()

           if (skuRes.error == null && skuRes.data != null) {
              const skus = skuRes.data as any[]
              for (let i = 0; i < skus.length; i++) {
                  let s = skus[i]
                  let sid: string = ''
                  if (s instanceof UTSJSONObject) {
                      sid = s.getString('id') ?? ''
                  } else {
                      const sObj = JSON.parse(JSON.stringify(s)) as UTSJSONObject
                      sid = sObj.getString('id') ?? ''
                  }

                  if (sid !== '') {
                      skuMap.set(sid, s)
                  }
              }
           }
      }
      
      // 处理返回数据，构建CartItem数组
      const cartItems: CartItem[] = []
      if ((cartData as any[]) != null) { // Simplify: cartData is already any[]
        const cartArray = cartData as any[]
        for (let i = 0; i < cartArray.length; i++) {
          let item = cartArray[i]
          let itemId: string = ''
          let userIdVal: string = ''
          let productId: string = ''
          let skuId: string = ''
          let quantity: number = 0
          let selected: boolean = false
          let createdAt: string = ''
          let updatedAt: string = ''
          let cartMerchantId: string = ''
          
          if (item instanceof UTSJSONObject) {
              itemId = item.getString('id') ?? ''
              userIdVal = item.getString('user_id') ?? ''
              productId = item.getString('product_id') ?? ''
              skuId = item.getString('sku_id') ?? ''
              quantity = item.getNumber('quantity') ?? 0
              selected = item.getBoolean('selected') ?? false
              createdAt = item.getString('created_at') ?? ''
              updatedAt = item.getString('updated_at') ?? ''
              cartMerchantId = item.getString('merchant_id') ?? ''
          } else {
              const iObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
              itemId = iObj.getString('id') ?? ''
              userIdVal = iObj.getString('user_id') ?? ''
              productId = iObj.getString('product_id') ?? ''
              skuId = iObj.getString('sku_id') ?? ''
              quantity = iObj.getNumber('quantity') ?? 0
              selected = iObj.getBoolean('selected') ?? false
              createdAt = iObj.getString('created_at') ?? ''
              updatedAt = iObj.getString('updated_at') ?? ''
              cartMerchantId = iObj.getString('merchant_id') ?? ''
          }
          
          const product = productMap.get(productId)
          const sku = (skuId !== '' && skuMap.has(skuId)) ? skuMap.get(skuId) : null
          
          console.log('[getCartItems] 处理购物车项:', itemId, 'productId:', productId, 'product存在:', product != null, 'sku存在:', sku != null)
          
          let merchantId: string = cartMerchantId
          let productName: string = ''
          let productImage: string = ''
          let productPrice: number = 0
          let productSpec: string = ''
          let shopNameStr: string = '未知店铺'

          if (product != null) {
              console.log('[getCartItems] product类型:', typeof product, 'instanceof UTSJSONObject:', product instanceof UTSJSONObject)
              if (product instanceof UTSJSONObject) {
                  // 优先使用购物车中的 merchant_id，如果没有则使用商品中的
                  if (merchantId == '') {
                      merchantId = product.getString('merchant_id') ?? ''
                  }
                  productName = product.getString('name') ?? ''
                  productImage = product.getString('main_image_url') ?? ''
                  productPrice = product.getNumber('base_price') ?? 0
                  console.log('[getCartItems] 从UTSJSONObject获取: name=', productName, 'price=', productPrice)
              } else {
                  const pObj = JSON.parse(JSON.stringify(product)) as UTSJSONObject
                  if (merchantId == '') {
                      merchantId = pObj.getString('merchant_id') ?? ''
                  }
                  productName = pObj.getString('name') ?? ''
                  productImage = pObj.getString('main_image_url') ?? ''
                  productPrice = pObj.getNumber('base_price') ?? 0
                  console.log('[getCartItems] 从普通对象获取: name=', productName, 'price=', productPrice)
              }
              // 从 shopMap 获取店铺名称
              if (merchantId !== '' && shopMap.has(merchantId)) {
                  shopNameStr = shopMap.get(merchantId) ?? '未知店铺'
              }
          }

          // 如果有SKU信息，覆盖价格、图片和规格
          if (sku != null) {
              if (sku instanceof UTSJSONObject) {
                  const skuPrice = sku.getNumber('price')
                  if (skuPrice != null && skuPrice > 0) {
                      productPrice = skuPrice
                  }
                  const skuImg = sku.getString('image_url')
                  if (skuImg != null && skuImg !== '') {
                      productImage = skuImg
                  }
                  
                  const specRaw = sku.get('specifications')
                  if (specRaw != null) {
                      if (typeof specRaw === 'string') {
                          productSpec = specRaw
                      } else if (specRaw instanceof UTSJSONObject) {
                          const keys = ['规格', '颜色', '尺码', '容量', '版本', '型号']
                          const result: string[] = []
                          for (let k = 0; k < keys.length; k++) {
                              const key = keys[k]
                              const val = specRaw.get(key)
                              if (val != null && val !== '') {
                                  result.push(`${val}`)
                              }
                          }
                          if (result.length > 0) {
                              productSpec = result.join(' ')
                          } else {
                              const allKeys = UTSJSONObject.keys(specRaw)
                              const parts: string[] = []
                              for(let k = 0; k < allKeys.length; k++) {
                                  let val = specRaw.get(allKeys[k])
                                  if (val != null) {
                                      parts.push(`${val}`)
                                  }
                              }
                              productSpec = parts.join(' ')
                          }
                      } else {
                          try {
                              let jsonStr = JSON.stringify(specRaw)
                              productSpec = jsonStr.replace(/["{}]/g, '').replace(/,/g, ' ').replace(/:/g, ' ')
                          } catch (e) {}
                      }
                  }
              } else {
                  const sObj = JSON.parse(JSON.stringify(sku)) as UTSJSONObject
                  const skuPrice = sObj.getNumber('price') ?? 0
                  if (skuPrice > 0) productPrice = skuPrice

                  const skuImg = sObj.getString('image_url') ?? ''
                  if (skuImg !== '') productImage = skuImg

                  const specRaw = sObj.get('specifications')
                  if (specRaw != null) {
                      if (typeof specRaw === 'string') {
                          productSpec = specRaw
                      } else if (specRaw instanceof UTSJSONObject) {
                          const keys = ['规格', '颜色', '尺码', '容量', '版本', '型号']
                          const result: string[] = []
                          for (let k = 0; k < keys.length; k++) {
                              const key = keys[k]
                              const val = specRaw.get(key)
                              if (val != null && val !== '') {
                                  result.push(`${val}`)
                              }
                          }
                          if (result.length > 0) {
                              productSpec = result.join(' ')
                          } else {
                              const allKeys = UTSJSONObject.keys(specRaw)
                              const parts: string[] = []
                              for(let k = 0; k < allKeys.length; k++) {
                                  let val = specRaw.get(allKeys[k])
                                  if (val != null) {
                                      parts.push(`${val}`)
                                  }
                              }
                              productSpec = parts.join(' ')
                          }
                      } else {
                          try {
                              let jsonStr = JSON.stringify(specRaw)
                              productSpec = jsonStr.replace(/["{}]/g, '').replace(/,/g, ' ').replace(/:/g, ' ')
                          } catch (e) {}
                      }
                  }
              }
          }

          let shopIdStr = merchantId != '' ? merchantId : 'unknown_shop'

          
          cartItems.push({
            id: itemId,
            user_id: userIdVal,
            product_id: productId,
            sku_id: skuId,
            merchant_id: merchantId,
            quantity: quantity,
            selected: selected,
            product_name: productName,
            product_image: productImage,
            product_price: productPrice,
            product_specification: productSpec,
            shop_id: shopIdStr,
            shop_name: shopNameStr,
            created_at: createdAt,
            updated_at: updatedAt
          } as CartItem)
        }
      }
      
      return cartItems
    } catch (error) {
      console.error('获取购物车异常:', error)
      return []
    }
  }

  // 获取用户通知 (系统、活动、订单)
  async getUserNotifications(type: string | null = null): Promise<Notification[]> {
    try {
      console.log('[getUserNotifications] 开始获取通知')
      const userId = this.getCurrentUserId()
      if (userId == null) return []

      let query = supa
        .from('ml_notifications')
        .select('*')
        .eq('user_id', userId)
        
      if (type != null) {
        query = query.eq('type', type)
      }
      
      const response = await query.order('created_at', { ascending: false }).execute()
      
      if (response.error != null) {
        console.error('获取通知失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) return []
      
      const notifications: Notification[] = []
      const rawList = rawData as any[]
      console.log('[getUserNotifications] 获取到通知数量:', rawList.length)
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const noteObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        const getSafeString = (key: string): string => {
          const val = noteObj.get(key)
          if (val == null) return ''
          if (typeof val == 'string') return val
          return ''
        }
        
        const getSafeNumber = (key: string): number => {
          const val = noteObj.get(key)
          if (val == null) return 0
          if (typeof val == 'number') return val
          return 0
        }
        
        const getSafeBoolean = (key: string): boolean => {
          const val = noteObj.get(key)
          if (val == null) return false
          if (typeof val == 'boolean') return val
          if (typeof val == 'number') return (val as number) == 1
          return false
        }
        
        const note: Notification = {
          id: getSafeString('id'),
          user_id: getSafeString('user_id'),
          type: getSafeString('type'),
          title: getSafeString('title'),
          content: getSafeString('content'),
          is_read: getSafeBoolean('is_read'),
          icon_url: getSafeString('icon_url'),
          link_url: getSafeString('link_url'),
          extra_data: getSafeString('extra_data'),
          created_at: getSafeString('created_at')
        }
        notifications.push(note)
      }
      return notifications
    } catch (e) {
      console.error('获取通知异常:', e)
      return []
    }
  }

  // 获取聊天会话列表
  async getChatRooms(): Promise<ChatRoom[]> {
    try {
      console.log('[getChatRooms] 开始获取聊天会话')
      const userId = this.getCurrentUserId()
      if (userId == null) return []

      const response = await supa
        .from('ml_chat_rooms')
        .select('*')
        .eq('user_id', userId)
        .order('updated_at', { ascending: false })
        .execute()
        
      if (response.error != null) {
        console.error('获取聊天会话失败:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) return []
      
      const rooms: ChatRoom[] = []
      const rawList = rawData as any[]
      console.log('[getChatRooms] 获取到会话数量:', rawList.length)
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const roomObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        const getSafeString = (key: string): string => {
          const val = roomObj.get(key)
          if (val == null) return ''
          if (typeof val == 'string') return val
          return ''
        }
        
        const getSafeNumber = (key: string): number => {
          const val = roomObj.get(key)
          if (val == null) return 0
          if (typeof val == 'number') return val
          return 0
        }
        
        const getSafeBoolean = (key: string): boolean => {
          const val = roomObj.get(key)
          if (val == null) return false
          if (typeof val == 'boolean') return val
          if (typeof val == 'number') return (val as number) == 1
          return false
        }
        
        const room: ChatRoom = {
          id: getSafeString('id'),
          user_id: getSafeString('user_id'),
          merchant_id: getSafeString('merchant_id'),
          shop_name: getSafeString('shop_name'),
          shop_logo: getSafeString('shop_logo'),
          last_message: getSafeString('last_message'),
          last_message_at: getSafeString('last_message_at'),
          unread_count: getSafeNumber('unread_count'),
          is_top: getSafeBoolean('is_top'),
          created_at: getSafeString('created_at'),
          updated_at: getSafeString('updated_at')
        }
        rooms.push(room)
      }
      return rooms
    } catch (e) {
       console.error('获取聊天会话异常:', e)
       return []
    }
  }

  // 获取用户聊天消息
  async getUserChatMessages(): Promise<ChatMessage[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return []

      const response = await supa
        .from('ml_chat_messages')
        .select('*')
        .or(`sender_id.eq.${userId},receiver_id.eq.${userId}`)
        .order('created_at', { ascending: false })
        .limit(50)
        .execute()
        
      if (response.error != null) {
        console.error('获取聊天记录失败:', response.error)
        return []
      }
      return response.data as ChatMessage[]
    } catch (e) {
       console.error('获取聊天记录异常:', e)
       return []
    }
  }

  // 获取与特定商家的聊天记录 (合并版本)
  async getChatMessages(merchantId: string, page: number = 1, pageSize: number = 20): Promise<ChatMessage[]> {
    try {
      console.log('[getChatMessages] 开始获取聊天记录，merchantId:', merchantId, 'page:', page)
      const userId = this.getCurrentUserId()
      if (userId == null) return []

      const fromIndex = (page - 1) * pageSize
      const toIndex = fromIndex + pageSize - 1

      // 使用 or 组合精确条件查询：(我发给商家) OR (商家发给我)
      const queryStr = `and(sender_id.eq.${userId},receiver_id.eq.${merchantId}),and(sender_id.eq.${merchantId},receiver_id.eq.${userId})`
      
      const response = await supa
        .from('ml_chat_messages')
        .select('*')
        .or(queryStr)
        .order('created_at', { ascending: false }) // 最新在前
        .range(fromIndex, toIndex)
        .execute()

      if (response.error != null) {
        console.error('getChatMessages error:', response.error)
        return []
      }
      
      const rawData = response.data
      if (rawData == null) return []
      
      const messages: ChatMessage[] = []
      const rawList = rawData as any[]
      console.log('[getChatMessages] 获取到消息数量:', rawList.length)
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const msgObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        const getSafeString = (key: string): string => {
          const val = msgObj.get(key)
          if (val == null) return ''
          return val.toString()
        }
        
        const getSafeBoolean = (key: string): boolean => {
          const val = msgObj.get(key)
          if (val == null) return false
          if (typeof val == 'boolean') return val as boolean
          return (val.toString() == '1' || val.toString() == 'true')
        }
        
        const msg: ChatMessage = {
          id: getSafeString('id'),
          session_id: getSafeString('session_id'),
          sender_id: getSafeString('sender_id'),
          receiver_id: getSafeString('receiver_id'),
          content: getSafeString('content'),
          msg_type: getSafeString('msg_type'),
          is_read: getSafeBoolean('is_read'),
          is_from_user: getSafeBoolean('is_from_user'),
          extra_data: getSafeString('extra_data'),
          created_at: getSafeString('created_at')
        }
        messages.push(msg)
      }
      return messages
    } catch (e) {
       console.error('获取聊天记录异常:', e)
       return []
    }
  }

  // 发送聊天消息
  async sendChatMessage(content: string, toId: string | null = null, type: string = 'text'): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false
          
          const payload = {
              sender_id: userId,
              content: content,
              msg_type: type,
              is_from_user: true,
              created_at: new Date().toISOString()
          } as UTSJSONObject
          if (toId != null) {
              payload.set('receiver_id', toId)
          }

          const response = await supa
              .from('ml_chat_messages')
              .insert(payload)
              .execute()
              
          if (response.error != null) {
              console.error('发送消息失败:', response.error)
              return false
          }
          return true
      } catch (e) {
          console.error('发送消息异常:', e)
          return false
      }
  }

  // 模拟客服回复
  async simulateServiceReply(content: string): Promise<boolean> {
       try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false

          const response = await supa
              .from('ml_chat_messages')
              .insert({
                  receiver_id: userId,
                  content: content,
                  msg_type: 'text',
                  is_from_user: false,
                  created_at: new Date().toISOString()
              })
              .execute()
           return response.error == null
       } catch (e) {
           return false
       }
  }

  // 添加商品到购物车
  async addToCart(productId: string, quantity: number = 1, skuId: string = '', merchantId: string = ''): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法添加商品到购物车')
        return false
      }
      
      const realSkuId = (skuId != null && skuId.length > 0) ? skuId : null
      const realMerchantId = (merchantId != null && merchantId.length > 0) ? merchantId : null

      // 检查商品是否已在购物车中
      // 注意：必须处理 sku_id 为空的情况，使用 is.null 过滤器
      let query = supa
        .from('ml_shopping_cart')
        .select('*')
        .eq('user_id', userId)
        .eq('product_id', productId)
      
      if (realSkuId != null) {
        query = query.eq('sku_id', realSkuId)
      } else {
        query = query.is('sku_id', null)
      }

      const existingResponse = await query.single().execute()

      let existingItem: any | null = null
      
      if (existingResponse.data != null) {
          const rawData = existingResponse.data as any
          if (Array.isArray(rawData)) {
              if (rawData.length > 0) {
                  existingItem = rawData[0]
              }
          } else {
              existingItem = rawData
          }
      }

      let response: AkReqResponse<any>
      if (existingItem != null) {
        // 商品已存在，更新数量
        console.log('Found existing cart item:', JSON.stringify(existingItem))

        // 确保 existingItem.id 存在
        let itemId: string | null = null
        let itemQty: any | null = null

        if (existingItem instanceof UTSJSONObject) {
            itemId = existingItem.getString('id')
            itemQty = existingItem.getNumber('quantity')
        } else {
             const obj = JSON.parse(JSON.stringify(existingItem)) as UTSJSONObject
             itemId = obj.getString('id')
             itemQty = obj.getNumber('quantity')
        }

        if (itemId != null) {
            let currentQty = 0
            if (typeof itemQty === 'number') {
                currentQty = itemQty as number
            } else {
                const qStr = `${itemQty ?? 0}`
                currentQty = parseInt(qStr)
            }
            const newQty = currentQty + quantity

            response = await supa
            .from('ml_shopping_cart')
            .update({
                quantity: newQty,
                merchant_id: realMerchantId,
                updated_at: new Date().toISOString()
            })
            .eq('id', itemId)
            .execute()
        } else {
            console.error('购物车已有商品但缺少ID，无法更新. Data:', JSON.stringify(existingItem))
            return false
        }
      } else {
        // 商品不存在，添加新记录
        const cartPayload = new UTSJSONObject()
        cartPayload.set('user_id', userId)
        cartPayload.set('product_id', productId)
        cartPayload.set('sku_id', realSkuId)
        cartPayload.set('quantity', quantity)
        cartPayload.set('selected', true)
        cartPayload.set('created_at', new Date().toISOString())
        cartPayload.set('updated_at', new Date().toISOString())
        if (realMerchantId != null) {
            cartPayload.set('merchant_id', realMerchantId)
        }
        
        response = await supa
          .from('ml_shopping_cart')
          .insert(cartPayload)
          .execute()
      }

      if (response.error != null) {
        console.error('添加商品到购物车失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('添加商品到购物车异常:', error)
      return false
    }
  }

  // 更新购物车商品数量
  async updateCartItemQuantity(cartItemId: string, quantity: number): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法更新购物车')
        return false
      }

      if (quantity < 1) {
        // 数量小于1时删除商品
        return await this.deleteCartItem(cartItemId)
      }

      const response = await supa
        .from('ml_shopping_cart')
        .update({
          quantity: quantity,
          updated_at: new Date().toISOString()
        })
        .eq('id', cartItemId)
        .eq('user_id', userId)
        .execute()

      if (response.error != null) {
        console.error('更新购物车商品数量失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('更新购物车商品数量异常:', error)
      return false
    }
  }

  // 更新购物车商品选中状态
  async updateCartItemSelection(cartItemId: string, selected: boolean): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法更新购物车')
        return false
      }

      const response = await supa
        .from('ml_shopping_cart')
        .update({
          selected: selected,
          updated_at: new Date().toISOString()
        })
        .eq('id', cartItemId)
        .eq('user_id', userId)
        .execute()

      if (response.error != null) {
        console.error('更新购物车商品选中状态失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('更新购物车商品选中状态异常:', error)
      return false
    }
  }

  // 批量更新购物车商品选中状态
  async batchUpdateCartItemSelection(cartItemIds: string[], selected: boolean): Promise<boolean> {
    try {
      console.log('[batchUpdateCartItemSelection] 开始批量更新')
      console.log('[batchUpdateCartItemSelection] cartItemIds:', JSON.stringify(cartItemIds))
      console.log('[batchUpdateCartItemSelection] cartItemIds length:', cartItemIds.length)
      console.log('[batchUpdateCartItemSelection] selected:', selected)
      
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法更新购物车')
        return false
      }

      const response = await supa
        .from('ml_shopping_cart')
        .update({
          selected: selected,
          updated_at: new Date().toISOString()
        })
        .eq('user_id', userId)
        .in('id', cartItemIds as any[])
        .execute()

      console.log('[batchUpdateCartItemSelection] response.error:', response.error)
      console.log('[batchUpdateCartItemSelection] response.data:', JSON.stringify(response.data))

      if (response.error != null) {
        console.error('批量更新购物车商品选中状态失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('批量更新购物车商品选中状态异常:', error)
      return false
    }
  }

  // 删除购物车商品
  async deleteCartItem(cartItemId: string): Promise<boolean> {
    try {
      console.log('正在执行删除购物车商品，ID:', cartItemId)
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法删除购物车商品')
        return false
      }

      const response = await supa
        .from('ml_shopping_cart')
        .eq('id', cartItemId)
        .eq('user_id', userId)
        .delete()
        .execute()

      if (response.error != null) {
        console.error('删除购物车商品失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('删除购物车商品异常:', error)
      return false
    }
  }

  // 批量删除购物车商品
  async batchDeleteCartItems(cartItemIds: string[]): Promise<boolean> {
    try {
      console.log('[batchDeleteCartItems] 开始删除, ids:', cartItemIds.length)
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法删除购物车商品')
        return false
      }

      console.log('[batchDeleteCartItems] userId:', userId)
      const response = await supa
        .from('ml_shopping_cart')
        .eq('user_id', userId)
        .in('id', cartItemIds as any[])
        .delete()
        .execute()

      console.log('[batchDeleteCartItems] response.error:', response.error)
      if (response.error != null) {
        console.error('批量删除购物车商品失败:', response.error)
        return false
      }

      console.log('[batchDeleteCartItems] 删除成功')
      return true
    } catch (error) {
      console.error('批量删除购物车商品异常:', error)
      return false
    }
  }

  // 清空购物车
  async clearCart(): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法清空购物车')
        return false
      }

      const response = await supa
        .from('ml_shopping_cart')
        .eq('user_id', userId)
        .delete()
        .execute()

      if (response.error != null) {
        console.error('清空购物车失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('清空购物车异常:', error)
      return false
    }
  }

  // 获取当前用户的所有地址
  async getAddresses(): Promise<UserAddress[]> {
    const userId = this.getCurrentUserId()
    if (userId == null) {
      console.warn('[getAddresses] 用户未登录，无法获取地址')
      return []
    }

    try {
      console.log('[getAddresses] 查询地址, userId:', userId)
      
      const response = await supa
        .from('ml_user_addresses')
        .select('*')
        .eq('user_id', userId)
        .order('is_default', { ascending: false })
        .order('created_at', { ascending: false })
        .execute()
      
      console.log('[getAddresses] response.error:', response.error)
      console.log('[getAddresses] response.data:', JSON.stringify(response.data))
      
      if (response.error != null) {
        console.error('[getAddresses] 获取地址失败:', response.error)
        return []
      }
      
      const data = response.data
      if (data == null) {
        return []
      }
      
      const result: UserAddress[] = []
      const rawData = data as any[]
      for (let i = 0; i < rawData.length; i++) {
        const item = rawData[i]
        let itemObj: UTSJSONObject
        if (item instanceof UTSJSONObject) {
          itemObj = item as UTSJSONObject
        } else {
          itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        }
        
        const addr: UserAddress = {
          id: itemObj.getString('id') ?? '',
          user_id: itemObj.getString('user_id') ?? '',
          recipient_name: itemObj.getString('receiver_name') ?? itemObj.getString('recipient_name') ?? '',
          phone: itemObj.getString('receiver_phone') ?? itemObj.getString('phone') ?? '',
          province: itemObj.getString('province') ?? '',
          city: itemObj.getString('city') ?? '',
          district: itemObj.getString('district') ?? '',
          detail_address: itemObj.getString('address_detail') ?? itemObj.getString('detail_address') ?? '',
          is_default: itemObj.getBoolean('is_default') ?? false,
          label: itemObj.getString('label') ?? '',
          latitude: itemObj.getNumber('latitude') ?? 0,
          longitude: itemObj.getNumber('longitude') ?? 0,
          coordinate_type: itemObj.getString('coordinate_type') ?? 'gcj02',
          created_at: itemObj.getString('created_at') ?? '',
          updated_at: itemObj.getString('updated_at') ?? ''
        }
        result.push(addr)
      }
      
      console.log('[getAddresses] 返回地址数量:', result.length)
      return result
    } catch (error) {
      console.error('[getAddresses] 获取地址异常:', error)
      return []
    }
  }

  // 根据ID获取地址详情
  async getAddressById(addressId: string): Promise<UserAddress | null> {
    const userId = this.getCurrentUserId()
    if (userId == null) {
      console.warn('用户未登录，无法获取地址')
      return null
    }

    try {
      const query = supa
        .from('ml_user_addresses')
        .select('*, recipient_name:receiver_name, phone:receiver_phone, detail_address:address_detail')
        .eq('id', addressId)
        .eq('user_id', userId)
        .single()
        
      const response = await query.execute()
      
      if (response.error != null) {
        console.error('获取地址详情失败:', response.error)
        return null
      }
      
      return response.data as UserAddress
    } catch (error) {
      console.error('获取地址详情异常:', error)
      return null
    }
  }

  // 添加新地址
  async addAddress(address: AddAddressParams): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法添加地址')
        return false
      }

      // 如果设置为默认地址，需要先取消其他默认地址
      if (address.is_default == true) {
        await this.clearDefaultAddress(userId)
      }

      const response = await supa
        .from('ml_user_addresses')
        .insert({
          user_id: userId,
          receiver_name: address.recipient_name,
          receiver_phone: address.phone,
          province: address.province,
          city: address.city,
          district: address.district,
          address_detail: address.detail_address,
          postal_code: address.postal_code ?? null,
          is_default: address.is_default ?? false,
          latitude: address.latitude ?? null,
          longitude: address.longitude ?? null,
          coordinate_type: address.coordinate_type ?? 'gcj02',
          created_at: new Date().toISOString(),
          updated_at: new Date().toISOString()
        })
        .execute()

      if (response.error != null) {
        console.error('添加地址失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('添加地址异常:', error)
      return false
    }
  }

  // 更新地址
  async updateAddress(addressId: string, address: UpdateAddressParams): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法更新地址')
        return false
      }

      // 如果设置为默认地址，需要先取消其他默认地址
      if (address.is_default == true) {
        await this.clearDefaultAddress(userId)
      }
      
      // 构造更新数据，映射字段名到数据库列名
      const updateData = {}
      if (address.recipient_name != null) updateData['receiver_name'] = address.recipient_name
      if (address.phone != null) updateData['receiver_phone'] = address.phone
      if (address.province != null) updateData['province'] = address.province
      if (address.city != null) updateData['city'] = address.city
      if (address.district != null) updateData['district'] = address.district
      if (address.detail_address != null) updateData['address_detail'] = address.detail_address
      if (address.postal_code != null) updateData['postal_code'] = address.postal_code
      if (address.is_default != null) updateData['is_default'] = address.is_default
      if (address.label != null) updateData['label'] = address.label
      if (address.latitude != null) updateData['latitude'] = address.latitude
      if (address.longitude != null) updateData['longitude'] = address.longitude
      if (address.coordinate_type != null) updateData['coordinate_type'] = address.coordinate_type
      updateData['updated_at'] = new Date().toISOString()

      const response = await supa
        .from('ml_user_addresses')
        .update(updateData)
        .eq('id', addressId)
        .eq('user_id', userId)
        .execute()

      if (response.error != null) {
        console.error('更新地址失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('更新地址异常:', error)
      return false
    }
  }
  
  // 确认收货
  async confirmReceipt(orderId: string): Promise<ConfirmReceiptResponse> {
    console.log('[confirmReceipt] 开始确认收货, orderId:', orderId)
    try {
      const userId = this.getCurrentUserId()
      console.log('[confirmReceipt] userId:', userId)
      if (userId == null) {
        return { success: false, error: '用户未登录' }
      }

      const updateData = new UTSJSONObject()
      updateData.set('order_status', 4)
      updateData.set('delivered_at', new Date().toISOString())
      updateData.set('completed_at', new Date().toISOString())
      updateData.set('updated_at', new Date().toISOString())
      
      console.log('[confirmReceipt] 准备更新订单状态, updateData:', JSON.stringify(updateData))

      const response = await supa
        .from('ml_orders')
        .update(updateData)
        .eq('id', orderId)
        .eq('user_id', userId)
        .execute()
      
      console.log('[confirmReceipt] response.status:', response.status)
      console.log('[confirmReceipt] response.error:', response.error)
      console.log('[confirmReceipt] response.data:', JSON.stringify(response.data))
      
      // 检查 HTTP 状态码
      if (response.status != null && response.status >= 400) {
        // 尝试从 response.data 中提取错误信息
        let errorMsg = '请求失败'
        if (response.data != null) {
          try {
            const errorData = response.data as UTSJSONObject
            const msg = errorData.getString('message')
            if (msg != null) {
              errorMsg = msg
            }
          } catch (e) {
            // ignore
          }
        }
        console.log('[confirmReceipt] HTTP错误:', response.status, errorMsg)
        return { success: false, error: errorMsg }
      }
      
      if (response.error != null) {
          return { success: false, error: response.error.message }
      }
      
      // 检查 response.data 是否包含错误代码
      if (response.data != null) {
        try {
          const respData = response.data as UTSJSONObject
          const errorCode = respData.getString('code')
          if (errorCode != null) {
            const errorMsg = respData.getString('message') ?? '数据库错误'
            console.log('[confirmReceipt] 数据库错误:', errorCode, errorMsg)
            return { success: false, error: errorMsg }
          }
        } catch (e) {
          // ignore
        }
      }
      
      // 检查是否有数据被更新
      if (response.data == null || (Array.isArray(response.data) && response.data.length === 0)) {
        console.log('[confirmReceipt] 没有数据被更新，可能订单不存在或无权限')
        return { success: false, error: '订单不存在或无权限更新' }
      }
      
      console.log('[confirmReceipt] 确认收货成功')
      return { success: true }
    } catch (e: any) {
        console.error('[confirmReceipt] 异常:', e)
        return { success: false, error: e.message }
    }
  }

  // 取消订单
  async cancelOrder(orderId: string, reason: string = '用户取消订单'): Promise<boolean> {
    return await this.cancelUnifiedOrder(orderId, 'goods', reason)
  }

  // 删除订单
  async deleteOrder(orderId: string): Promise<boolean> {
    return await this.softDeleteUnifiedOrderForConsumer(orderId, 'goods')
  }

  async softDeleteOrderForConsumer(orderId: string): Promise<boolean> {
    return await this.softDeleteUnifiedOrderForConsumer(orderId, 'goods')
  }

  // 确认收货
  async confirmOrderReceived(orderId: string): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        return false
      }

      const response = await supa
        .from('ml_orders')
        .update({
          order_status: 4,
          shipping_status: 3,
          updated_at: new Date().toISOString()
        })
        .eq('id', orderId)
        .eq('user_id', userId)
        .execute()
      
      if (response.error != null) {
        console.error('确认收货失败:', response.error)
        return false
      }
      
      return true
    } catch (e) {
      console.error('确认收货异常:', e)
      return false
    }
  }

  // 删除地址
  async deleteAddress(addressId: string): Promise<boolean> {
    try {
      console.log('正在执行删除地址，ID:', addressId)
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法删除地址')
        return false
      }

      const response = await supa
        .from('ml_user_addresses')
        .eq('id', addressId)
        .eq('user_id', userId)
        .delete()
        .execute()

      if (response.error != null) {
        console.error('删除地址失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('删除地址异常:', error)
      return false
    }
  }

  // 清除默认地址（内部使用）
  private async clearDefaultAddress(userId: string): Promise<void> {
    try {
      await supa
        .from('ml_user_addresses')
        .update({
          is_default: false,
          updated_at: new Date().toISOString()
        })
        .eq('user_id', userId)
        .eq('is_default', true)
        .execute()
    } catch (error) {
      console.error('清除默认地址异常:', error)
    }
  }

  // 获取用户资料
  async getUserProfile(): Promise<any | null> {
    try {
       const userId = this.getCurrentUserId()
       if (userId == null) return null
       
       // 联合查询 auth user 和 profile
       // 由于 Supabase auth table 不可直接访问，这里查询 ml_user_profiles
       // 注意：使用 limit(1) 替代 single() 以避免 Android 端类型转换错误
       const response = await supa
         .from('ml_user_profiles')
         .select('*')
         .eq('user_id', userId)
         .limit(1)
         .execute()
         
       if (response.error != null) {
          // 如果不存在 profile，可能只有 auth user，这里暂时返回空或创建默认
          return null
       }
       
       const rawData = response.data
       if (rawData == null) return null
       
       // 作为数组处理
       const rawList = rawData as any[]
       if (rawList.length == 0) return null
       
       return rawList[0]
    } catch (e) {
       return null
    }
  }
  
  // 创建订单
  async createOrder(orderData: CreateOrderParams): Promise<string | null> {
      try {
        const userId = this.getCurrentUserId()
        if (userId == null) {
          console.error('CreateOrder: User not logged in')
          return null
        }
        
        const orderNo = 'ML' + Date.now() + Math.floor(Math.random() * 1000)
        
        let merchantId = orderData.merchant_id
        console.log('[CreateOrder] 原始 merchant_id:', merchantId)
        if (merchantId == null || merchantId == '' || merchantId == 'unknown') {
          console.warn('[CreateOrder] merchant_id 为空或无效，将使用 userId 作为 fallback')
          merchantId = userId
        }
        console.log('[CreateOrder] 最终使用的 merchant_id:', merchantId)
        
        let shippingAddrStr = '{}'
        if (orderData.shipping_address != null) {
          if (typeof orderData.shipping_address === 'string') {
            shippingAddrStr = orderData.shipping_address
          } else {
            shippingAddrStr = JSON.stringify(orderData.shipping_address)
          }
        }
        
        const orderPayload = new UTSJSONObject()
        orderPayload.set('user_id', userId)
        orderPayload.set('merchant_id', merchantId)
        orderPayload.set('order_no', orderNo)
        orderPayload.set('product_amount', orderData.product_amount)
        orderPayload.set('shipping_fee', orderData.shipping_fee)
        orderPayload.set('total_amount', orderData.total_amount)
        orderPayload.set('paid_amount', 0)
        orderPayload.set('shipping_address', shippingAddrStr)
        orderPayload.set('order_status', ORDER_STATUS_PENDING)
        orderPayload.set('payment_status', PAYMENT_STATUS_UNPAID)
        orderPayload.set('pay_expire_at', new Date(Date.now() + ORDER_PAY_TIMEOUT_SECONDS * 1000).toISOString())
        orderPayload.set('consumer_deleted_at', null)
        orderPayload.set('shipping_status', 1)
        orderPayload.set('created_at', new Date().toISOString())
        orderPayload.set('updated_at', new Date().toISOString())

        console.log('[CreateOrder] 插入订单数据:', JSON.stringify(orderPayload))
        console.log('[CreateOrder] 期望的订单号:', orderNo)
        
        const orderResponse = await supa
            .from('ml_orders')
            .insert(orderPayload)
            .execute()
            
        console.log('[CreateOrder] insert 完成')
        console.log('[CreateOrder] orderResponse.error:', orderResponse.error)
            
        if (orderResponse.error != null) {
            console.error('[CreateOrder] 创建订单失败:', orderResponse.error)
            return null
        }
        
        console.log('[CreateOrder] 开始查询新创建的订单, order_no:', orderNo)
        
        const queryResponse = await supa
            .from('ml_orders')
            .select('id, order_no')
            .eq('order_no', orderNo)
            .execute()
            
        console.log('[CreateOrder] queryResponse.error:', queryResponse.error)
        console.log('[CreateOrder] queryResponse.data:', JSON.stringify(queryResponse.data))
        
        if (queryResponse.error != null) {
            console.error('[CreateOrder] 查询订单失败:', queryResponse.error)
            return null
        }
        
        const queryData = queryResponse.data as any
        let orderId = ''
        
        console.log('[CreateOrder] queryData 类型:', typeof queryData, '是否数组:', Array.isArray(queryData))
        
        if (Array.isArray(queryData) && queryData.length > 0) {
            console.log('[CreateOrder] queryData 长度:', queryData.length)
            const firstItemRaw = queryData[0]
            console.log('[CreateOrder] firstItemRaw 类型:', typeof firstItemRaw)
            
            // 将 firstItemRaw 转换为可访问的对象
            const firstItemStr = JSON.stringify(firstItemRaw)
            const firstItemParsed = JSON.parse(firstItemStr)
            if (firstItemParsed == null) {
                console.error('[CreateOrder] 解析订单数据失败')
                return null
            }
            const firstItem = firstItemParsed as UTSJSONObject
            orderId = (firstItem.getString('id') ?? '') as string
            console.log('[CreateOrder] 找到新创建的订单, id:', orderId)
        } else {
            console.error('[CreateOrder] 未找到新创建的订单，插入可能失败')
            return null
        }
        
        console.log('[CreateOrder] 订单创建成功, orderId:', orderId)
        
        const orderItems: UTSJSONObject[] = []
        console.log('[CreateOrder] orderData.items 类型:', typeof orderData.items, '是否数组:', Array.isArray(orderData.items))
        
        if (orderData.items == null) {
            console.error('[CreateOrder] orderData.items 为 null!')
            return orderId
        }
        
        const rawItems = orderData.items as any[]
        console.log('[CreateOrder] rawItems 长度:', rawItems.length)
        
        if (rawItems.length === 0) {
            console.warn('[CreateOrder] rawItems 为空数组，没有商品项需要插入')
            return orderId
        }
        
        for(let i = 0; i < rawItems.length; i++) {
            const rawItem = rawItems[i]
            const itemStr = JSON.stringify(rawItem)
            const itemParsed = JSON.parse(itemStr)
            if (itemParsed == null) {
                console.error('[CreateOrder] 商品项解析失败')
                continue
            }
            const item = itemParsed as UTSJSONObject

            const itemJson = new UTSJSONObject()
            
            let pId = item.get('product_id')
            if (pId == null) {
              pId = item.get('id')
            }
            const productId = (pId ?? '') as string
            
            itemJson.set('order_id', orderId)
            itemJson.set('product_id', productId)
            
            const skuIdVal = item.get('sku_id')
            if (skuIdVal != null && skuIdVal !== '') {
                itemJson.set('sku_id', skuIdVal as string)
            }
            
            const productName = (item.get('product_name') ?? '') as string
            itemJson.set('product_name', productName)
            
            const sName = item.get('sku_name')
            itemJson.set('sku_name', (sName ?? '') as string)
            
            const specVal = item.get('specifications')
            let skuSnapshot = '{}'
            if (specVal != null) {
                if (typeof specVal === 'string') {
                    skuSnapshot = specVal as string
                } else {
                    skuSnapshot = JSON.stringify(specVal)
                }
            }
            itemJson.set('sku_snapshot', skuSnapshot)
            itemJson.set('specifications', skuSnapshot)
            
            const img1 = item.get('product_image')
            const img2 = item.get('image_url')
            let imgUrl = ((img1 ?? img2 ?? '') as string)
            while (imgUrl.indexOf('`') >= 0) {
                imgUrl = imgUrl.replace('`', '')
            }
            itemJson.set('image_url', imgUrl)

            const iPriceRaw = item.getNumber('price') ?? 0
            const iMemberPrice = item.getNumber('member_price') ?? 0
            // 优先使用会员价
            const iPrice = (iMemberPrice > 0 && iMemberPrice < iPriceRaw) ? iMemberPrice : iPriceRaw
            const iQty = item.getNumber('quantity') ?? 1
            itemJson.set('price', iPrice)
            itemJson.set('quantity', iQty)
            itemJson.set('total_amount', iPrice * iQty)
            itemJson.set('created_at', new Date().toISOString())
            
            orderItems.push(itemJson)
        }
        
        console.log('[CreateOrder] 插入订单项数量:', orderItems.length)
        
        for (let j: number = 0; j < orderItems.length; j++) {
            console.log('[CreateOrder] 开始插入订单项', j)
            const itemJson = orderItems[j]
            // 将 UTSJSONObject 转换为普通对象
            console.log('[CreateOrder] 序列化订单项...')
            const itemObjStr = JSON.stringify(itemJson)
            console.log('[CreateOrder] 订单项 JSON:', itemObjStr)
            const itemObjParsed = JSON.parse(itemObjStr)
            console.log('[CreateOrder] itemObjParsed 类型:', typeof itemObjParsed)
            if (itemObjParsed == null) {
                console.error('[CreateOrder] 订单项转换失败')
                continue
            }
            
            // 使用 UTSJSONObject 而不是 Record<string, any>
            const itemObj = itemObjParsed as UTSJSONObject
            console.log('[CreateOrder] 执行 insert...')
            
            const itemsResponse = await supa
                .from('ml_order_items')
                .insert(itemObj)
                .execute()
            
            console.log('[CreateOrder] insert 完成, error:', itemsResponse.error)    
            if (itemsResponse.error != null) {
                console.error('[CreateOrder] 创建订单项失败:', itemsResponse.error)
            }
        }
        
        console.log('[CreateOrder] 订单项创建成功')
        
        const cartItemIds: string[] = []
        for(let i = 0; i < rawItems.length; i++) {
            const rawItem = rawItems[i]
            const itemParsed = JSON.parse(JSON.stringify(rawItem))
            if (itemParsed == null) continue
            const item = itemParsed as UTSJSONObject
            const iid = item.getString('id')
            if (iid != null && iid.length > 10) {
                cartItemIds.push(iid)
            }
        }
        
        if (cartItemIds.length > 0) {
            await this.batchDeleteCartItems(cartItemIds)
        }
        
        return orderId
      } catch (error) {
          console.error('[CreateOrder] 创建订单异常:', error)
          return null
      }
  }

      async ensurePayExpireAt(orderId: string): Promise<string> {
        return await this.ensureUnifiedPayExpireAt(orderId, 'goods')
      }

      async markOrderPaymentCancelled(orderId: string): Promise<boolean> {
        return await this.markUnifiedOrderPaymentCancelled(orderId, 'goods')
      }

      async expireOrder(orderId: string): Promise<boolean> {
        return await this.expireUnifiedOrder(orderId, 'goods')
      }

  // 批量通过店铺创建订单
  async createOrdersByShop(params: ShopOrderParams): Promise<ShopOrderResponse> {
    try {
        const orderIds: string[] = []
        const groups = params.shopGroups as any[]
        
        let grandTotal = 0.0
        for(let k = 0; k < groups.length; k++) {
             const g = JSON.parse(JSON.stringify(groups[k])) as UTSJSONObject
             const gItemsRaw = g.get('items')
             if (gItemsRaw == null) continue
             const gItems = gItemsRaw as any[]
             
             for(let gi = 0; gi < gItems.length; gi++) {
                 const it = JSON.parse(JSON.stringify(gItems[gi])) as UTSJSONObject
                 // 优先使用会员价
                 let itPrice = it.getNumber('price') ?? 0
                 const itMemberPrice = it.getNumber('member_price') ?? 0
                 if (itMemberPrice > 0 && itMemberPrice < itPrice) {
                     itPrice = itMemberPrice
                 }
                 const itQty = it.getNumber('quantity') ?? 1
                 grandTotal += itPrice * itQty
             }
        }
        
        // 为每个店铺创建一个订单
        for (let i = 0; i < groups.length; i++) {
            const group = JSON.parse(JSON.stringify(groups[i])) as UTSJSONObject
            const shopItemsRaw = group.get('items')
            if (shopItemsRaw == null) continue
            const shopItems = shopItemsRaw as any[]
            
            let productAmount = 0.0
            for(let j = 0; j < shopItems.length; j++) {
                const sItem = JSON.parse(JSON.stringify(shopItems[j])) as UTSJSONObject
                // 优先使用会员价
                let siPrice = sItem.getNumber('price') ?? 0
                const siMemberPrice = sItem.getNumber('member_price') ?? 0
                if (siMemberPrice > 0 && siMemberPrice < siPrice) {
                    siPrice = siMemberPrice
                }
                const siQty = sItem.getNumber('quantity') ?? 1
                productAmount += siPrice * siQty
            }
            
            // 简单平摊运费和优惠 (实际逻辑可能更复杂)
            const ratio = grandTotal > 0 ? (productAmount / grandTotal) : 0
            const shopShippingFee = params.deliveryFee * ratio
            const shopDiscount = params.discountAmount * ratio
            const shopTotal = productAmount + shopShippingFee - shopDiscount
            
            const mId = group.getString('merchant_id')
            const sId = group.getString('shopId')
            const shopName = group.getString('shopName')

            console.log('[createOrdersByShop] 店铺组信息:', {
                merchant_id: mId,
                shopId: sId,
                shopName: shopName
            })

            const finalMerchantId = (mId != null && mId != '') ? mId : (sId ?? '')
            console.log('[createOrdersByShop] 最终使用的 merchant_id:', finalMerchantId)
            
            // 将 shopItems 转换为普通对象数组
            const plainItems: any[] = []
            for(let k = 0; k < shopItems.length; k++) {
                const plainItemRaw = JSON.parse(JSON.stringify(shopItems[k]))
                if (plainItemRaw != null) {
                    plainItems.push(plainItemRaw as any)
                }
            }
            console.log('[createOrdersByShop] plainItems 数量:', plainItems.length)

            const orderId = await this.createOrder({
                merchant_id: finalMerchantId,
                product_amount: productAmount,
                shipping_fee: shopShippingFee,
                total_amount: shopTotal,
                shipping_address: params.shipping_address,
                items: plainItems
            })
            
            if (orderId != null) {
                orderIds.push(orderId)
            } else {
                return { success: false, orderIds, error: `店铺 ${shopName} 订单创建失败` }
            }
        }
        
        return { success: true, orderIds }
    } catch (e) {
        console.error('批量创建订单异常:', e)
        return { success: false, orderIds: [], error: '系统异常' }
    }
  }

  // 获取订单列表
  async getOrders(status: number = 0): Promise<any[]> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
             const empty: any[] = []
             return empty
          }
          
          // 关联查询店铺表获取店铺名称
          let query = supa
            .from('ml_orders')
            .select('*, ml_order_items(*), ml_shops(shop_name)')
            .eq('user_id', userId)
            .is('consumer_deleted_at', null)
            .order('created_at', { ascending: false })
            
          if (status > 0) {
              query = query.eq('order_status', status)
          }
          
          const response = await query.execute()
          
          console.log('[getOrders] response.error:', response.error)
          if (response.data != null && Array.isArray(response.data)) {
              console.log('[getOrders] 订单数量:', response.data.length)
          }
          
          if (response.error != null) {
              console.error('获取订单列表失败:', response.error)
              const empty: any[] = []
              return empty
          }
          
          const data = response.data
          if (data == null) {
              const empty: any[] = []
              return empty
          }
          
          // 修复订单项中的图片URL
          const orders = data as any[]
          for (let i = 0; i < orders.length; i++) {
              const order = orders[i]
              const orderStr = JSON.stringify(order)
              const orderObj = JSON.parse(orderStr) as UTSJSONObject
              const itemsRaw = orderObj.get('ml_order_items')
              if (itemsRaw != null && Array.isArray(itemsRaw)) {
                  const items = itemsRaw as any[]
                  for (let j = 0; j < items.length; j++) {
                      const item = items[j]
                      const itemStr = JSON.stringify(item)
                      const itemObj = JSON.parse(itemStr) as UTSJSONObject
                      const imgUrl = itemObj.getString('image_url')
                      if (imgUrl != null) {
                          itemObj['image_url'] = fixImageUrl(imgUrl)
                      }
                      const prodImg = itemObj.getString('product_image')
                      if (prodImg != null) {
                          itemObj['product_image'] = fixImageUrl(prodImg)
                      }
                      items[j] = itemObj
                  }
                  orderObj['ml_order_items'] = items
                  orders[i] = orderObj
              }
          }
          
          return orders
      } catch (error) {
          console.error('获取订单列表异常:', error)
          const empty: any[] = []
          return empty
      }
  }

      private normalizeOrderList(orderList: UTSJSONObject[]): UTSJSONObject[] {
        for (let i = 0; i < orderList.length; i++) {
          const order = orderList[i]
          const orderStr = JSON.stringify(order)
          const orderObj = JSON.parse(orderStr) as UTSJSONObject
          const itemsRaw = orderObj.get('ml_order_items')
          if (itemsRaw != null && Array.isArray(itemsRaw)) {
            const items = itemsRaw as UTSJSONObject[]
            for (let j = 0; j < items.length; j++) {
              const item = items[j]
              const itemStr = JSON.stringify(item)
              const itemObj = JSON.parse(itemStr) as UTSJSONObject
              const imgUrl = itemObj.getString('image_url')
              if (imgUrl != null) {
                itemObj['image_url'] = fixImageUrl(imgUrl)
              }
              const prodImg = itemObj.getString('product_image')
              if (prodImg != null) {
                itemObj['product_image'] = fixImageUrl(prodImg)
              }
              items[j] = itemObj
            }
            orderObj['ml_order_items'] = items
            orderList[i] = orderObj
          }
        }
        return orderList
      }

      private appendUniqueString(list: string[], value: string | null): void {
        if (value == null || value == '') {
          return
        }
        for (let i = 0; i < list.length; i++) {
          if (list[i] == value) {
            return
          }
        }
        list.push(value)
      }

      private async getKeywordMatchedOrderIds(userId: string, keyword: string): Promise<string[]> {
        const matchedIds: string[] = []
        const keywordPattern = '%' + keyword + '%'

        try {
          const orderResponse = await supa
          .from('ml_orders')
          .select('id')
          .eq('user_id', userId)
          .ilike('order_no', keywordPattern)
          .limit(200)
          .execute()

          if (orderResponse.error == null && orderResponse.data != null && Array.isArray(orderResponse.data)) {
            const orderRows = orderResponse.data as UTSJSONObject[]
            for (let i = 0; i < orderRows.length; i++) {
              const rowStr = JSON.stringify(orderRows[i])
              const rowObj = JSON.parse(rowStr) as UTSJSONObject
              this.appendUniqueString(matchedIds, rowObj.getString('id'))
            }
          }
        } catch (error) {
          console.error('[getKeywordMatchedOrderIds] 订单号搜索异常:', error)
        }

        try {
          const itemResponse = await supa
          .from('ml_order_items')
          .select('order_id')
          .ilike('product_name', keywordPattern)
          .limit(200)
          .execute()

          if (itemResponse.error == null && itemResponse.data != null && Array.isArray(itemResponse.data)) {
            const itemRows = itemResponse.data as UTSJSONObject[]
            for (let i = 0; i < itemRows.length; i++) {
              const rowStr = JSON.stringify(itemRows[i])
              const rowObj = JSON.parse(rowStr) as UTSJSONObject
              this.appendUniqueString(matchedIds, rowObj.getString('order_id'))
            }
          }
        } catch (error) {
          console.error('[getKeywordMatchedOrderIds] 商品名搜索异常:', error)
        }

        return matchedIds
      }

      private normalizeServiceStatus(status: string): string {
        if (status == 'ORDER_CREATED') return 'created'
        if (status == 'ORDER_ASSIGNED') return 'assigned'
        if (status == 'ORDER_ACCEPTED') return 'accepted'
        if (status == 'ORDER_REJECTED') return 'rejected'
        if (status == 'ORDER_CHECKED_IN') return 'arrived'
        if (status == 'ORDER_IN_SERVICE') return 'in_service'
        if (status == 'ORDER_COMPLETED' || status == 'ACCEPTANCE_PENDING') return 'pending_acceptance'
        if (status == 'ACCEPTED') return 'accepted_by_user'
        if (status == 'SETTLEMENT_READY' || status == 'ARCHIVED') return 'settled'
        if (status == 'ORDER_CANCELLED') return 'cancelled'
        if (status == 'ORDER_EXCEPTION' || status == 'ACCEPTANCE_REJECTED') return 'exception'
        if (status == 'created' || status == 'submitted') return 'created'
        if (status == 'paid') return 'paid'
        if (status == 'assigned' || status == 'pending_dispatch' || status == 'pending_assignment') return 'assigned'
        if (status == 'accepted' || status == 'pending_accept') return 'accepted'
        if (status == 'rejected') return 'rejected'
        if (status == 'departed' || status == 'waiting_departure' || status == 'on_the_way') return 'departed'
        if (status == 'arrived' || status == 'checked_in') return 'arrived'
        if (status == 'in_service' || status == 'serving') return 'in_service'
        if (status == 'completed') return 'completed'
        if (status == 'pending_acceptance' || status == 'pending_confirm' || status == 'pending_submit') return 'pending_acceptance'
        if (status == 'accepted_by_user') return 'accepted_by_user'
        if (status == 'reviewed') return 'reviewed'
        if (status == 'settled') return 'settled'
        if (status == 'cancelled') return 'cancelled'
        return 'exception'
      }

      private getUnifiedServiceStatusNumber(status: string): number {
        const normalizedStatus = this.normalizeServiceStatus(status)
        if (normalizedStatus == 'created') return 1
        if (normalizedStatus == 'paid' || normalizedStatus == 'assigned') return 2
        if (normalizedStatus == 'accepted' || normalizedStatus == 'departed') return 3
        if (normalizedStatus == 'arrived' || normalizedStatus == 'in_service') return 4
        if (normalizedStatus == 'completed' || normalizedStatus == 'pending_acceptance' || normalizedStatus == 'accepted_by_user' || normalizedStatus == 'reviewed' || normalizedStatus == 'settled') return 5
        if (normalizedStatus == 'cancelled' || normalizedStatus == 'rejected' || normalizedStatus == 'exception') return 8
        return 3
      }

      private matchesServiceStatusTab(status: string, statusTab: string): boolean {
        if (statusTab == 'all') return true
        const normalizedStatus = this.normalizeServiceStatus(status)
        if (statusTab == 'pending') return normalizedStatus == 'created'
        if (statusTab == 'accepted') return normalizedStatus == 'paid' || normalizedStatus == 'assigned'
        if (statusTab == 'scheduled') return normalizedStatus == 'accepted' || normalizedStatus == 'departed'
        if (statusTab == 'inservice') return normalizedStatus == 'arrived' || normalizedStatus == 'in_service'
        if (statusTab == 'completed') return normalizedStatus == 'completed' || normalizedStatus == 'pending_acceptance' || normalizedStatus == 'accepted_by_user' || normalizedStatus == 'reviewed' || normalizedStatus == 'settled'
        if (statusTab == 'aftersale') return false
        if (statusTab == 'inprogress') return normalizedStatus == 'paid' || normalizedStatus == 'assigned' || normalizedStatus == 'accepted' || normalizedStatus == 'departed' || normalizedStatus == 'arrived' || normalizedStatus == 'in_service'
        return true
      }

      private formatServiceAppointmentText(value: string): string {
        if (value == '') {
          return ''
        }
        if (value.indexOf('上午') >= 0 || value.indexOf('下午') >= 0 || value.indexOf('晚上') >= 0) {
          return value
        }
        const parsed = Date.parse(value)
        if (!isNaN(parsed)) {
          const date = new Date(parsed)
          let year = date.getFullYear()
          const currentYear = new Date().getFullYear()
          if (year < currentYear - 1) {
            year = currentYear
          }
          const month = String(date.getMonth() + 1).padStart(2, '0')
          const day = String(date.getDate()).padStart(2, '0')
          const hour = String(date.getHours()).padStart(2, '0')
          const minute = String(date.getMinutes()).padStart(2, '0')
          return year + '-' + month + '-' + day + ' ' + hour + ':' + minute
        }
        const monthDayMatch = value.match(/(\d{2})\/(\d{2})/)
        const timeMatch = value.match(/(\d{2}:\d{2}(\s*-\s*\d{2}:\d{2})?)/)
        if (monthDayMatch != null) {
          const month = monthDayMatch[1] ?? ''
          const day = monthDayMatch[2] ?? ''
          const timeText = timeMatch != null ? (timeMatch[1] ?? '') : ''
          if (month != '' && day != '') {
            return String(new Date().getFullYear()) + '-' + month + '-' + day + (timeText != '' ? ' ' + timeText.replace(/\s+/g, '') : '')
          }
        }
        return value.replace('T', ' ')
      }

      private buildUnifiedServiceOrder(rawOrder: any): UTSJSONObject {
        const orderObj = JSON.parse(JSON.stringify(rawOrder)) as UTSJSONObject
        const addressSnapshotRaw = orderObj.get('address_snapshot_json')
        const serviceSnapshotRaw = orderObj.get('service_snapshot_json')
        let addressObj: UTSJSONObject | null = null
        let serviceObj: UTSJSONObject | null = null

        try {
          if (addressSnapshotRaw != null) {
            const addressText = JSON.stringify(addressSnapshotRaw)
            if (addressText.startsWith('"')) {
              addressObj = JSON.parse(orderObj.getString('address_snapshot_json') ?? '{}') as UTSJSONObject
            } else {
              addressObj = JSON.parse(addressText) as UTSJSONObject
            }
          }
        } catch (e) {
          addressObj = null
        }

        try {
          if (serviceSnapshotRaw != null) {
            const serviceText = JSON.stringify(serviceSnapshotRaw)
            if (serviceText.startsWith('"')) {
              serviceObj = JSON.parse(orderObj.getString('service_snapshot_json') ?? '{}') as UTSJSONObject
            } else {
              serviceObj = JSON.parse(serviceText) as UTSJSONObject
            }
          }
        } catch (e) {
          serviceObj = null
        }

        const normalizedStatus = this.getUnifiedServiceStatusNumber(orderObj.getString('status') ?? '')
        const fullAddress = addressObj != null ? (addressObj.getString('fullAddress') ?? '') : ''
        const providerName = orderObj.getString('staff_name') ?? ''
        const serviceName = orderObj.getString('service_name') ?? (serviceObj != null ? (serviceObj.getString('serviceName') ?? '') : '')
        const servicePrice = serviceObj != null ? (serviceObj.getNumber('price') ?? 0) : 0

        const serviceInfo = new UTSJSONObject()
        serviceInfo.set('service_name', serviceName)
        serviceInfo.set('service_image', '/static/images/default.png')
        serviceInfo.set('appointment_time', this.formatServiceAppointmentText(orderObj.getString('appointment_time') ?? ''))
        serviceInfo.set('address', fullAddress)
        serviceInfo.set('contact_name', orderObj.getString('contact_name') ?? '')
        serviceInfo.set('contact_phone', orderObj.getString('contact_phone') ?? '')
        serviceInfo.set('provider_name', providerName)

        const unifiedOrder = new UTSJSONObject()
        const rawPaymentStatus = orderObj.getNumber('payment_status')
        let paymentStatus = rawPaymentStatus ?? 0
        if (paymentStatus <= 0) {
          if (normalizedStatus == ORDER_STATUS_PENDING) {
            paymentStatus = PAYMENT_STATUS_UNPAID
          } else if (normalizedStatus == ORDER_STATUS_CANCELLED || normalizedStatus == ORDER_STATUS_TIMEOUT_LEGACY) {
            paymentStatus = PAYMENT_STATUS_TIMEOUT
          } else {
            paymentStatus = 2
          }
        }
        unifiedOrder.set('id', orderObj.getString('id') ?? '')
        unifiedOrder.set('order_no', orderObj.getString('order_no') ?? '')
        unifiedOrder.set('biz_type', 'service')
        unifiedOrder.set('source', 'service')
        unifiedOrder.set('status', normalizedStatus)
        unifiedOrder.set('order_status', normalizedStatus)
        unifiedOrder.set('payment_status', paymentStatus)
        unifiedOrder.set('pay_expire_at', orderObj.getString('pay_expire_at') ?? '')
        unifiedOrder.set('cancel_reason', orderObj.getString('cancel_reason') ?? '')
        unifiedOrder.set('created_at', orderObj.getString('created_at') ?? '')
        unifiedOrder.set('create_time', orderObj.getString('created_at') ?? '')
        unifiedOrder.set('product_amount', servicePrice)
        unifiedOrder.set('shipping_fee', 0)
        unifiedOrder.set('total_amount', servicePrice)
        unifiedOrder.set('paid_amount', servicePrice)
        unifiedOrder.set('merchant_id', orderObj.getString('current_staff_id') ?? '')
        unifiedOrder.set('shop_name', providerName != '' ? providerName : '康养上门服务')
        unifiedOrder.set('service_info', serviceInfo)
        unifiedOrder.set('ml_order_items', [] as UTSJSONObject[])
        return unifiedOrder
      }

      private async getServiceOrdersByCursor(params: GetUnifiedOrdersByCursorParams): Promise<GetUnifiedOrdersByCursorResult> {
        const emptyResult: GetUnifiedOrdersByCursorResult = {
          list: [] as UTSJSONObject[],
          nextCursor: '',
          hasMore: false
        }

        try {
          const userId = this.getCurrentUserId()
          if (userId == null || userId == '') {
            return emptyResult
          }

          let query = supa
            .from('hss_service_orders')
            .select('*')
            .eq('user_id', userId)
            .is('consumer_deleted_at', null)
            .order('created_at', { ascending: false })
            .limit(200)

          const cursor = params.cursor.trim()
          if (cursor != '') {
            query = query.lt('created_at', cursor)
          }

          const response = await query.execute()
          if (response.error != null || response.data == null || !Array.isArray(response.data)) {
            return emptyResult
          }

          const keyword = params.keyword.trim()
          const filtered = [] as UTSJSONObject[]
          const rawList = response.data as any[]
          for (let i = 0; i < rawList.length; i++) {
            const rawItem = rawList[i]
            const rawObj = JSON.parse(JSON.stringify(rawItem)) as UTSJSONObject
            const orderNo = rawObj.getString('order_no') ?? ''
            const serviceName = rawObj.getString('service_name') ?? ''
            const contactName = rawObj.getString('contact_name') ?? ''
            const appointmentTime = rawObj.getString('appointment_time') ?? ''
            const addressSnapshot = rawObj.getString('address_snapshot_json') ?? ''
            const matchedKeyword = keyword == '' || orderNo.indexOf(keyword) >= 0 || serviceName.indexOf(keyword) >= 0 || contactName.indexOf(keyword) >= 0 || appointmentTime.indexOf(keyword) >= 0 || addressSnapshot.indexOf(keyword) >= 0
            if (!matchedKeyword) {
              continue
            }
            if (!this.matchesServiceStatusTab(rawObj.getString('status') ?? '', params.statusTab)) {
              continue
            }
            filtered.push(this.buildUnifiedServiceOrder(rawItem))
          }

          const limit = params.limit <= 0 ? 10 : params.limit
          let hasMore = false
          let list = filtered
          if (filtered.length > limit) {
            hasMore = true
            list = filtered.slice(0, limit)
          }

          let nextCursor = ''
          if (list.length > 0) {
            const lastOrder = list[list.length - 1]
            nextCursor = lastOrder.getString('created_at') ?? ''
          }

          return {
            list,
            nextCursor,
            hasMore
          }
        } catch (error) {
          console.error('[getServiceOrdersByCursor] 查询异常:', error)
          return emptyResult
        }
      }

      async getUnifiedOrdersByCursor(params: GetUnifiedOrdersByCursorParams): Promise<GetUnifiedOrdersByCursorResult> {
        const emptyResult: GetUnifiedOrdersByCursorResult = {
          list: [] as UTSJSONObject[],
          nextCursor: '',
          hasMore: false
        }

        try {
          if (params.bizType == 'service') {
            return await this.getServiceOrdersByCursor(params)
          }

          if (params.bizType == 'goods') {
            const goodsResult = await this.getOrdersByCursor({
              cursor: params.cursor,
              limit: params.limit,
              status: params.statusTab == 'pending' ? 1 : params.statusTab == 'shipping' ? 2 : params.statusTab == 'delivering' ? 3 : params.statusTab == 'completed' ? 4 : params.statusTab == 'aftersale' ? 6 : 0,
              keyword: params.keyword
            })
            return {
              list: goodsResult.list,
              nextCursor: goodsResult.nextCursor,
              hasMore: goodsResult.hasMore
            }
          }

          const goodsStatus = params.statusTab == 'pending' ? 1 : params.statusTab == 'completed' ? 4 : params.statusTab == 'aftersale' ? 6 : 0
          const goodsResult = await this.getOrdersByCursor({
            cursor: '',
            limit: 200,
            status: goodsStatus,
            keyword: params.keyword
          })
          const serviceResult = await this.getServiceOrdersByCursor({
            cursor: '',
            limit: 200,
            bizType: 'service',
            statusTab: params.statusTab,
            keyword: params.keyword
          })

          let mergedList = [] as UTSJSONObject[]
          for (let i = 0; i < goodsResult.list.length; i++) {
            const goodsItem = goodsResult.list[i]
            const status = goodsItem.getNumber('order_status') ?? 0
            const includeGoods = params.statusTab == 'all' || (params.statusTab == 'pending' && status == 1) || (params.statusTab == 'completed' && status == 4) || (params.statusTab == 'aftersale' && (status == 6 || status == 7)) || (params.statusTab == 'inprogress' && (status == 2 || status == 3))
            if (includeGoods) {
              mergedList.push(goodsItem)
            }
          }
          for (let i = 0; i < serviceResult.list.length; i++) {
            mergedList.push(serviceResult.list[i])
          }

          mergedList.sort((left: UTSJSONObject, right: UTSJSONObject): number => {
            const leftTime = left.getString('created_at') ?? ''
            const rightTime = right.getString('created_at') ?? ''
            if (leftTime == rightTime) return 0
            return leftTime > rightTime ? -1 : 1
          })

          const cursor = params.cursor.trim()
          if (cursor != '') {
            const cursorFiltered = [] as UTSJSONObject[]
            for (let i = 0; i < mergedList.length; i++) {
              const createdAt = mergedList[i].getString('created_at') ?? ''
              if (createdAt < cursor) {
                cursorFiltered.push(mergedList[i])
              }
            }
            mergedList = cursorFiltered
          }

          const limit = params.limit <= 0 ? 10 : params.limit
          let hasMore = false
          let list = mergedList
          if (mergedList.length > limit) {
            hasMore = true
            list = mergedList.slice(0, limit)
          }

          let nextCursor = ''
          if (list.length > 0) {
            nextCursor = list[list.length - 1].getString('created_at') ?? ''
          }

          return {
            list,
            nextCursor,
            hasMore
          }
        } catch (error) {
          console.error('[getUnifiedOrdersByCursor] 查询异常:', error)
          return emptyResult
        }
      }

      async getServiceOrderStatusCounts(): Promise<UTSJSONObject> {
        const counts = new UTSJSONObject()
        counts.set('all', 0)
        counts.set('pending', 0)
        counts.set('accepted', 0)
        counts.set('scheduled', 0)
        counts.set('inservice', 0)
        counts.set('completed', 0)
        counts.set('aftersale', 0)

        try {
          const userId = this.getCurrentUserId()
          if (userId == null || userId == '') {
            return counts
          }

          const response = await supa
            .from('hss_service_orders')
            .select('status')
            .eq('user_id', userId)
            .is('consumer_deleted_at', null)
            .limit(500)
            .execute()

          if (response.error != null || response.data == null || !Array.isArray(response.data)) {
            return counts
          }

          const rawList = response.data as any[]
          counts.set('all', rawList.length)
          for (let i = 0; i < rawList.length; i++) {
            const rawObj = JSON.parse(JSON.stringify(rawList[i])) as UTSJSONObject
            const normalizedStatus = this.normalizeServiceStatus(rawObj.getString('status') ?? '')
            if (normalizedStatus == 'created') {
              counts.set('pending', (counts.getNumber('pending') ?? 0) + 1)
            } else if (normalizedStatus == 'paid' || normalizedStatus == 'assigned') {
              counts.set('accepted', (counts.getNumber('accepted') ?? 0) + 1)
            } else if (normalizedStatus == 'accepted' || normalizedStatus == 'departed') {
              counts.set('scheduled', (counts.getNumber('scheduled') ?? 0) + 1)
            } else if (normalizedStatus == 'arrived' || normalizedStatus == 'in_service') {
              counts.set('inservice', (counts.getNumber('inservice') ?? 0) + 1)
            } else if (normalizedStatus == 'completed' || normalizedStatus == 'pending_acceptance' || normalizedStatus == 'accepted_by_user' || normalizedStatus == 'reviewed' || normalizedStatus == 'settled') {
              counts.set('completed', (counts.getNumber('completed') ?? 0) + 1)
            }
          }
          return counts
        } catch (error) {
          console.error('[getServiceOrderStatusCounts] 统计异常:', error)
          return counts
        }
      }

      async getOrdersByCursor(params: GetOrdersByCursorParams): Promise<GetOrdersByCursorResult> {
        const emptyResult: GetOrdersByCursorResult = {
          list: [] as UTSJSONObject[],
          nextCursor: '',
          hasMore: false
        }

        try {
          const userId = this.getCurrentUserId()
          if (userId == null || userId == '') {
            return emptyResult
          }

          const limit = params.limit <= 0 ? 10 : params.limit
          const queryLimit = limit + 1

          let query = supa
          .from('ml_orders')
          .select('*, ml_order_items(*), ml_shops(shop_name)')
          .eq('user_id', userId)
          .is('consumer_deleted_at', null)
          .order('created_at', { ascending: false })
          .limit(queryLimit)

          if (params.status > 0) {
            if (params.status == 6) {
              query = query.in('order_status', [6, 7])
            } else {
              query = query.eq('order_status', params.status)
            }
          }

          const keyword = params.keyword.trim()
          if (keyword != '') {
            const matchedOrderIds = await this.getKeywordMatchedOrderIds(userId, keyword)
            if (matchedOrderIds.length == 0) {
              return emptyResult
            }
            query = query.in('id', matchedOrderIds)
          }

          const cursor = params.cursor.trim()
          if (cursor != '') {
            query = query.lt('created_at', cursor)
          }

          const response = await query.execute()
          if (response.error != null) {
            console.error('[getOrdersByCursor] 查询失败:', response.error)
            throw response.error
          }

          const rawData = response.data
          if (rawData == null || !Array.isArray(rawData)) {
            return emptyResult
          }

          const rawList = rawData as UTSJSONObject[]
          let hasMore = false
          let list = rawList
          if (rawList.length > limit) {
            hasMore = true
            list = rawList.slice(0, limit)
          }

          const normalizedList = this.normalizeOrderList(list)

          let nextCursor = ''
          if (normalizedList.length > 0) {
            const lastOrder = normalizedList[normalizedList.length - 1]
            const lastOrderStr = JSON.stringify(lastOrder)
            const lastOrderObj = JSON.parse(lastOrderStr) as UTSJSONObject
            nextCursor = lastOrderObj.getString('created_at') ?? ''
          }

          return {
            list: normalizedList,
            nextCursor: nextCursor,
            hasMore: hasMore
          }
        } catch (error) {
          console.error('[getOrdersByCursor] 查询异常:', error)
          return emptyResult
        }
      }

      async getOrderCounts(): Promise<OrderCountsResult> {
        const emptyCounts: OrderCountsResult = {
          all: 0,
          pending: 0,
          shipping: 0,
          delivering: 0,
          completed: 0,
          aftersale: 0,
          cancelled: 0
        }

        try {
          const userId = this.getCurrentUserId()
          if (userId == null || userId == '') {
            return emptyCounts
          }

          const queryCount = async (statusList: number[]): Promise<number> => {
            let query = supa
            .from('ml_orders')
            .select('*', { count: 'exact' })
            .eq('user_id', userId)
            .is('consumer_deleted_at', null)
            .limit(1)

            if (statusList.length == 1) {
              query = query.eq('order_status', statusList[0])
            } else if (statusList.length > 1) {
              query = query.in('order_status', statusList)
            }

            const response = await query.execute()
            if (response.error != null) {
              console.error('[getOrderCounts] 统计失败:', response.error)
              return 0
            }

            return response.total ?? 0
          }

          const all = await queryCount([])
          const pending = await queryCount([1])
          const shipping = await queryCount([2])
          const delivering = await queryCount([3])
          const completed = await queryCount([4])
          const aftersale = await queryCount([6, 7])
          const cancelled = await queryCount([5])

          return {
            all,
            pending,
            shipping,
            delivering,
            completed,
            aftersale,
            cancelled
          }
        } catch (error) {
          console.error('[getOrderCounts] 统计异常:', error)
          return emptyCounts
        }
      }
  
    isUuidOrderId(orderId: string): boolean {
      if (orderId == null || orderId == '') {
        return false
      }
      const normalized = orderId.toLowerCase()
      const parts = normalized.split('-')
      if (parts.length != 5) {
        return false
      }
      const expectedLengths = [8, 4, 4, 4, 12]
      for (let i = 0; i < parts.length; i++) {
        const part = parts[i]
        if (part.length != expectedLengths[i]) {
          return false
        }
        for (let j = 0; j < part.length; j++) {
          const ch = part.charAt(j)
          const isDigit = ch >= '0' && ch <= '9'
          const isHexLower = ch >= 'a' && ch <= 'f'
          if (!isDigit && !isHexLower) {
            return false
          }
        }
      }
      return true
    }

    private isServiceOrderSource(orderId: string, source: string): boolean {
      return source == 'service' || orderId.startsWith('so-')
    }

    private getUnifiedOrderTableName(orderId: string, source: string): string {
      return this.isServiceOrderSource(orderId, source) ? 'hss_service_orders' : 'ml_orders'
    }

    private logUnifiedOrderRoute(action: string, orderId: string, source: string, tableName: string): void {
      console.log('[' + action + '] source =', source)
      console.log('[' + action + '] orderId =', orderId)
      console.log('[' + action + '] tableName =', tableName)
    }

    private logPostgrestFailure(action: string, response: any): void {
      console.error('[' + action + '] 请求失败:', response?.error)
      console.error('[' + action + '] response.data:', JSON.stringify(response?.data))
      console.error('[' + action + '] response.status:', response?.status)
    }

    private buildUnifiedGoodsOrderResult(rawOrder: any): UTSJSONObject {
      const orderObj = JSON.parse(JSON.stringify(rawOrder)) as UTSJSONObject
      const result = new UTSJSONObject()
      result.set('id', orderObj.get('id') ?? '')
      result.set('order_no', orderObj.get('order_no') ?? '')
      result.set('biz_type', 'goods')
      result.set('source', 'goods')
      result.set('status', orderObj.get('order_status') ?? 1)
      result.set('order_status', orderObj.get('order_status') ?? 1)
      result.set('user_id', orderObj.get('user_id') ?? '')
      result.set('merchant_id', orderObj.get('merchant_id') ?? '')
      result.set('product_amount', orderObj.get('product_amount') ?? 0)
      result.set('shipping_fee', orderObj.get('shipping_fee') ?? 0)
      result.set('total_amount', orderObj.get('total_amount') ?? 0)
      result.set('paid_amount', orderObj.get('paid_amount') ?? 0)
      result.set('discount_amount', orderObj.get('discount_amount') ?? 0)
      result.set('payment_method', orderObj.get('payment_method') ?? '')
      result.set('payment_status', orderObj.get('payment_status') ?? 1)
      result.set('cancel_reason', orderObj.get('cancel_reason') ?? '')
      result.set('pay_expire_at', orderObj.get('pay_expire_at') ?? '')
      result.set('consumer_deleted_at', orderObj.get('consumer_deleted_at') ?? '')
      result.set('shipping_status', orderObj.get('shipping_status') ?? 1)
      result.set('created_at', orderObj.get('created_at') ?? '')
      result.set('paid_at', orderObj.get('paid_at') ?? '')
      result.set('shipped_at', orderObj.get('shipped_at') ?? '')
      result.set('completed_at', orderObj.get('completed_at') ?? '')
      result.set('shipping_address', orderObj.get('shipping_address'))
      result.set('ml_order_items', orderObj.get('ml_order_items'))
      result.set('items', orderObj.get('ml_order_items'))
      result.set('ml_shops', orderObj.get('ml_shops'))
      result.set('tracking_no', orderObj.get('tracking_no') ?? '')
      result.set('carrier_name', orderObj.get('carrier_name') ?? '')
      result.set('delivered_at', orderObj.get('delivered_at') ?? '')
      return result
    }

    private buildUnifiedServiceOrderDetailResult(rawOrder: any): UTSJSONObject {
      const orderObj = JSON.parse(JSON.stringify(rawOrder)) as UTSJSONObject
      const unifiedOrder = this.buildUnifiedServiceOrder(rawOrder)
      const appointmentTime = this.formatServiceAppointmentText(orderObj.getString('appointment_time') ?? '')
      const fullAddress = unifiedOrder.get('service_info')
      let serviceInfo = new UTSJSONObject()
      if (fullAddress != null) {
        serviceInfo = JSON.parse(JSON.stringify(fullAddress)) as UTSJSONObject
      }

      const contactName = orderObj.getString('contact_name') ?? ''
      const contactPhone = orderObj.getString('contact_phone') ?? ''
      const addressText = serviceInfo.getString('address') ?? ''

      const shippingAddress = new UTSJSONObject()
      shippingAddress.set('name', contactName)
      shippingAddress.set('phone', contactPhone)
      shippingAddress.set('address', addressText)
      shippingAddress.set('detail', addressText)
      shippingAddress.set('province', '')
      shippingAddress.set('city', '')
      shippingAddress.set('district', '')

      const item = new UTSJSONObject()
      item.set('id', orderObj.getString('id') ?? '')
      item.set('product_id', orderObj.getString('service_id') ?? '')
      item.set('product_name', serviceInfo.getString('service_name') ?? (orderObj.getString('service_name') ?? '服务订单'))
      item.set('sku_name', appointmentTime)
      item.set('spec', appointmentTime)
      item.set('product_image', serviceInfo.getString('service_image') ?? '/static/images/default.png')
      item.set('image', serviceInfo.getString('service_image') ?? '/static/images/default.png')
      item.set('price', unifiedOrder.getNumber('total_amount') ?? 0)
      item.set('quantity', 1)

      const items = [] as UTSJSONObject[]
      items.push(item)

      unifiedOrder.set('status', unifiedOrder.getNumber('order_status') ?? 1)
      unifiedOrder.set('shipping_address', shippingAddress)
      unifiedOrder.set('items', items)
      unifiedOrder.set('service_info', serviceInfo)
      unifiedOrder.set('contact_name', contactName)
      unifiedOrder.set('contact_phone', contactPhone)
      unifiedOrder.set('appointment_time', appointmentTime)
      unifiedOrder.set('address', addressText)
      unifiedOrder.set('payment_method', '')
      unifiedOrder.set('discount_amount', 0)
      unifiedOrder.set('paid_at', '')
      unifiedOrder.set('shipped_at', '')
      unifiedOrder.set('completed_at', orderObj.getString('completed_at') ?? '')
      return unifiedOrder
    }

    async getUnifiedOrderDetail(orderId: string, source: string): Promise<UTSJSONObject | null> {
      try {
        const userId = this.getCurrentUserId()
        if (userId == null || userId == '') {
          return null
        }

        const tableName = this.getUnifiedOrderTableName(orderId, source)
        this.logUnifiedOrderRoute('getUnifiedOrderDetail', orderId, source, tableName)

        if (tableName == 'hss_service_orders') {
          const response = await supa
            .from('hss_service_orders')
            .select('*')
            .eq('user_id', userId)
            .is('consumer_deleted_at', null)
            .or(`id.eq.${orderId},order_no.eq.${orderId}`)
            .limit(1)
            .execute()

          console.log('[getUnifiedOrderDetail] response.data =', JSON.stringify(response.data))
          if (response.error != null) {
            this.logPostgrestFailure('getUnifiedOrderDetail', response)
            return null
          }
          const rawList = response.data as any[]
          if (rawList == null || rawList.length == 0) {
            console.log('[getUnifiedOrderDetail] 未找到订单')
            return null
          }
          return this.buildUnifiedServiceOrderDetailResult(rawList[0])
        }

        const response = await supa
          .from('ml_orders')
          .select('*, ml_order_items(*), ml_shops(shop_name)')
          .eq('user_id', userId)
          .is('consumer_deleted_at', null)
          .or(`id.eq.${orderId},order_no.eq.${orderId}`)
          .limit(1)
          .execute()

        console.log('[getUnifiedOrderDetail] response.data =', JSON.stringify(response.data))
        if (response.error != null) {
          this.logPostgrestFailure('getUnifiedOrderDetail', response)
          return null
        }
        const rawList = response.data as any[]
        if (rawList == null || rawList.length == 0) {
          console.log('[getUnifiedOrderDetail] 未找到订单')
          return null
        }
        return this.buildUnifiedGoodsOrderResult(rawList[0])
      } catch (e) {
        console.error('[getUnifiedOrderDetail] 获取订单详情异常:', e)
        return null
      }
    }

    async ensureUnifiedPayExpireAt(orderId: string, source: string): Promise<string> {
      try {
        const latestOrder = await this.getUnifiedOrderDetail(orderId, source)
        if (latestOrder == null) {
          return ''
        }

        const currentExpireAt = latestOrder.getString('pay_expire_at') ?? ''
        if (currentExpireAt != '') {
          return currentExpireAt
        }

        const createdAt = latestOrder.getString('created_at') ?? ''
        const createdDate = new Date(createdAt)
        if (createdAt == '' || isNaN(createdDate.getTime())) {
          return ''
        }

        const expireAtIso = new Date(createdDate.getTime() + ORDER_PAY_TIMEOUT_SECONDS * 1000).toISOString()
        const userId = this.getCurrentUserId()
        if (userId == null || userId == '') {
          return ''
        }

        const tableName = this.getUnifiedOrderTableName(orderId, source)
        this.logUnifiedOrderRoute('ensureUnifiedPayExpireAt', orderId, source, tableName)
        const response = await supa
          .from(tableName)
          .update({
            pay_expire_at: expireAtIso,
            updated_at: new Date().toISOString()
          })
          .eq('user_id', userId)
          .or(`id.eq.${orderId},order_no.eq.${orderId}`)
          .is('pay_expire_at', null)
          .execute()

        if (response.error != null) {
          this.logPostgrestFailure('ensureUnifiedPayExpireAt', response)
          return ''
        }
        return expireAtIso
      } catch (e) {
        console.error('[ensureUnifiedPayExpireAt] 异常:', e)
        return ''
      }
    }

    async cancelUnifiedOrder(orderId: string, source: string, reason: string = '用户取消订单'): Promise<boolean> {
      try {
        const userId = this.getCurrentUserId()
        if (userId == null || userId == '') {
          return false
        }
        const tableName = this.getUnifiedOrderTableName(orderId, source)
        const isService = tableName == 'hss_service_orders'
        this.logUnifiedOrderRoute('cancelUnifiedOrder', orderId, source, tableName)
        const nowIso = new Date().toISOString()

        const updatePayload = new UTSJSONObject()
        updatePayload.set('payment_status', PAYMENT_STATUS_TIMEOUT)
        updatePayload.set('cancel_reason', reason)
        updatePayload.set('cancelled_at', nowIso)
        updatePayload.set('updated_at', nowIso)
        if (isService) {
          updatePayload.set('status', 'cancelled')
        } else {
          updatePayload.set('order_status', ORDER_STATUS_CANCELLED)
        }

        const response = await supa
          .from(tableName)
          .update(updatePayload)
          .eq('user_id', userId)
          .or(`id.eq.${orderId},order_no.eq.${orderId}`)
          .execute()

        if (response.error != null) {
          this.logPostgrestFailure('cancelUnifiedOrder', response)
          return false
        }
        return response.data != null && (!Array.isArray(response.data) || response.data.length > 0)
      } catch (e) {
        console.error('[cancelUnifiedOrder] 异常:', e)
        return false
      }
    }

    async expireUnifiedOrder(orderId: string, source: string): Promise<boolean> {
      try {
        const latestOrder = await this.getUnifiedOrderDetail(orderId, source)
        if (latestOrder == null) {
          return false
        }
        const latestStatus = latestOrder.getNumber('order_status') ?? ORDER_STATUS_PENDING
        const latestPaymentStatus = latestOrder.getNumber('payment_status') ?? PAYMENT_STATUS_UNPAID
        const latestCancelReason = latestOrder.getString('cancel_reason') ?? ''
        const latestExpireAt = latestOrder.getString('pay_expire_at') ?? ''
        if (latestStatus == ORDER_STATUS_CANCELLED || latestStatus == ORDER_STATUS_TIMEOUT_LEGACY || latestPaymentStatus == PAYMENT_STATUS_TIMEOUT || latestCancelReason.indexOf('超时') >= 0) {
          return true
        }

        let effectiveExpireAt = latestExpireAt
        if (effectiveExpireAt == '') {
          effectiveExpireAt = await this.ensureUnifiedPayExpireAt(orderId, source)
        }
        const expireMs = effectiveExpireAt != '' ? new Date(effectiveExpireAt).getTime() : 0
        if (expireMs <= 0 || expireMs > Date.now()) {
          return false
        }

        return await this.cancelUnifiedOrder(orderId, source, ORDER_TIMEOUT_CANCEL_REASON)
      } catch (e) {
        console.error('[expireUnifiedOrder] 异常:', e)
        return false
      }
    }

    async softDeleteUnifiedOrderForConsumer(orderId: string, source: string): Promise<boolean> {
      try {
        const userId = this.getCurrentUserId()
        if (userId == null || userId == '') {
          return false
        }
        const tableName = this.getUnifiedOrderTableName(orderId, source)
        this.logUnifiedOrderRoute('softDeleteUnifiedOrderForConsumer', orderId, source, tableName)
        const response = await supa
          .from(tableName)
          .update({
            consumer_deleted_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
          })
          .eq('user_id', userId)
          .or(`id.eq.${orderId},order_no.eq.${orderId}`)
          .execute()

        if (response.error != null) {
          this.logPostgrestFailure('softDeleteUnifiedOrderForConsumer', response)
          return false
        }
        return response.data != null && (!Array.isArray(response.data) || response.data.length > 0)
      } catch (e) {
        console.error('[softDeleteUnifiedOrderForConsumer] 异常:', e)
        return false
      }
    }

    async markUnifiedOrderPaymentCancelled(orderId: string, source: string): Promise<boolean> {
      try {
        const userId = this.getCurrentUserId()
        if (userId == null || userId == '') {
          return false
        }
        const tableName = this.getUnifiedOrderTableName(orderId, source)
        const isService = tableName == 'hss_service_orders'
        this.logUnifiedOrderRoute('markUnifiedOrderPaymentCancelled', orderId, source, tableName)

        const updatePayload = new UTSJSONObject()
        updatePayload.set('payment_status', PAYMENT_STATUS_UNPAID)
        updatePayload.set('updated_at', new Date().toISOString())
        if (isService) {
          updatePayload.set('status', 'created')
        } else {
          updatePayload.set('order_status', ORDER_STATUS_PENDING)
        }

        const response = await supa
          .from(tableName)
          .update(updatePayload)
          .eq('user_id', userId)
          .or(`id.eq.${orderId},order_no.eq.${orderId}`)
          .execute()

        if (response.error != null) {
          this.logPostgrestFailure('markUnifiedOrderPaymentCancelled', response)
          return false
        }
        return true
      } catch (e) {
        console.error('[markUnifiedOrderPaymentCancelled] 异常:', e)
        return false
      }
    }

    async payUnifiedOrder(orderId: string, source: string, paymentMethod: string, amount: number): Promise<boolean> {
      try {
        const userId = this.getCurrentUserId()
        if (userId == null || userId == '') {
          console.error('[payUnifiedOrder] 用户未登录')
          return false
        }

        const latestOrder = await this.getUnifiedOrderDetail(orderId, source)
        if (latestOrder == null) {
          console.error('[payUnifiedOrder] 订单不存在，无法支付')
          return false
        }

        const latestStatus = latestOrder.getNumber('order_status') ?? ORDER_STATUS_PENDING
        const latestPaymentStatus = latestOrder.getNumber('payment_status') ?? PAYMENT_STATUS_UNPAID
        const latestCancelReason = latestOrder.getString('cancel_reason') ?? ''
        const latestPayExpireAt = latestOrder.getString('pay_expire_at') ?? ''
        const expireMs = latestPayExpireAt != '' ? new Date(latestPayExpireAt).getTime() : 0
        const isExpired = latestStatus == ORDER_STATUS_CANCELLED || latestStatus == ORDER_STATUS_TIMEOUT_LEGACY || latestPaymentStatus == PAYMENT_STATUS_TIMEOUT || latestCancelReason.indexOf('超时') >= 0 || (expireMs > 0 && expireMs <= Date.now())

        if (isExpired) {
          await this.expireUnifiedOrder(orderId, source)
          console.error('[payUnifiedOrder] 订单已超时，拒绝支付')
          return false
        }
        if (latestStatus != ORDER_STATUS_PENDING || latestPaymentStatus != PAYMENT_STATUS_UNPAID) {
          console.error('[payUnifiedOrder] 订单状态已变更，拒绝支付:', latestStatus, latestPaymentStatus)
          return false
        }

        const tableName = this.getUnifiedOrderTableName(orderId, source)
        const isService = tableName == 'hss_service_orders'
        this.logUnifiedOrderRoute('payUnifiedOrder', orderId, source, tableName)
        const nowIso = new Date().toISOString()

        const updatePayload = new UTSJSONObject()
        updatePayload.set('payment_status', PAYMENT_STATUS_PAID)
        updatePayload.set('updated_at', nowIso)
        if (isService) {
          updatePayload.set('status', 'paid')
        } else {
          updatePayload.set('order_status', ORDER_STATUS_PAID_OR_SHIPPING)
          updatePayload.set('payment_method', paymentMethod)
          updatePayload.set('paid_at', nowIso)
          updatePayload.set('paid_amount', amount)
        }

        let query = supa
          .from(tableName)
          .update(updatePayload)
          .eq('user_id', userId)
          .eq('payment_status', PAYMENT_STATUS_UNPAID)
          .or(`id.eq.${orderId},order_no.eq.${orderId}`)

        if (isService) {
          query = query.eq('status', 'created')
        } else {
          query = query.eq('order_status', ORDER_STATUS_PENDING)
        }
        if (latestPayExpireAt != '') {
          query = query.gt('pay_expire_at', nowIso)
        }

        const response = await query.execute()
        if (response.error != null) {
          this.logPostgrestFailure('payUnifiedOrder', response)
          return false
        }
        if (response.data == null || (Array.isArray(response.data) && response.data.length === 0)) {
          console.error('[payUnifiedOrder] 没有订单被更新，支付前状态校验未通过')
          return false
        }
        return true
      } catch (e) {
        console.error('[payUnifiedOrder] 支付异常:', e)
        return false
      }
    }

    // 获取订单详情
  async getOrderDetail(orderId: string): Promise<any | null> {
      return await this.getUnifiedOrderDetail(orderId, 'goods')
  }

  // 支付订单
  async payOrder(orderId: string, paymentMethod: string, amount: number): Promise<boolean> {
      return await this.payUnifiedOrder(orderId, 'goods', paymentMethod, amount)
  }

  // 根据ID获取订单信息
  async getOrderById(orderId: string): Promise<UTSJSONObject | null> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              console.error('[getOrderById] 用户未登录')
              return null
          }
          
          console.log('[getOrderById] 查询订单, orderId:', orderId)
          
            const query = supa
              .from('ml_orders')
                try {
                  const result = await this.getUnifiedOrderDetail(orderId, 'goods')
                  if (result == null) {
                  return null
                  }
                  return result
                } catch (e) {
                  console.error('[getOrderById] 查询订单异常:', e)
                  return null
                }
      const refundType = d.getNumber('refund_type')
      const refundReason = d.getString('refund_reason')
      const refundAmount = d.getNumber('refund_amount')
      const description = d.getString('description')
      const images = d.getArray('images')
      
      console.log('[createRefund] orderId:', orderId)
      console.log('[createRefund] refundType:', refundType)
      console.log('[createRefund] refundReason:', refundReason)
      console.log('[createRefund] refundAmount:', refundAmount)

      const payload = {
        user_id: userId,
        order_id: orderId,
        refund_no: 'REF' + Date.now() + Math.floor(Math.random() * 1000),
        refund_type: refundType,
        refund_reason: refundReason,
        refund_amount: refundAmount,
        description: description ?? '',
        images: images ?? ([] as any[]),
        status: 1 // Pending
      }
      
      console.log('[createRefund] 准备插入 ml_refunds')
      const response = await supa
        .from('ml_refunds')
        .insert(payload)
        .execute()
        
      console.log('[createRefund] insert response.error:', response.error)
        
      if (response.error != null) {
        console.error('提交售后失败:', response.error)
        return { success: false, message: '提交失败: ' + (response.error.message ?? '未知错误') }
      }
      
      console.log('[createRefund] 插入成功，更新订单状态')
      // 更新订单状态为退款中
      const updateResponse = await supa
        .from('ml_orders')
        .update({
          order_status: 6, // 退款中
          updated_at: new Date().toISOString()
        })
        .eq('id', orderId)
        .execute()
      
      console.log('[createRefund] update response.error:', updateResponse.error)
      
      if (updateResponse.error != null) {
        console.error('更新订单状态失败:', updateResponse.error)
        // 不影响退款申请结果，只记录错误
      }
      
      console.log('[createRefund] 完成，返回成功')
      return { success: true, message: '申请提交成功' }
    } catch (e) {
      console.error('提交售后异常:', e)
      return { success: false, message: '系统异常' }
    }
  }

  // 取消退款申请
  async cancelRefund(orderId: string): Promise<RefundResponse> {
    try {
      console.log('[cancelRefund] 开始取消退款申请, orderId:', orderId)
      const userId = this.getCurrentUserId()
      if (userId == null) {
        return { success: false, message: '请先登录' }
      }
      
      // 更新退款记录状态为已取消
      const refundUpdateResponse = await supa
        .from('ml_refunds')
        .update({
          status: 4, // 已取消
          updated_at: new Date().toISOString()
        })
        .eq('order_id', orderId)
        .eq('user_id', userId)
        .eq('status', 1) // 只能取消待处理的退款
        .execute()
      
      if (refundUpdateResponse.error != null) {
        console.error('取消退款记录失败:', refundUpdateResponse.error)
        return { success: false, message: '取消失败: ' + (refundUpdateResponse.error.message ?? '未知错误') }
      }
      
      // 恢复订单状态为已完成（假设之前是已完成状态）
      const orderUpdateResponse = await supa
        .from('ml_orders')
        .update({
          order_status: 4, // 已完成
          updated_at: new Date().toISOString()
        })
        .eq('id', orderId)
        .execute()
      
      if (orderUpdateResponse.error != null) {
        console.error('恢复订单状态失败:', orderUpdateResponse.error)
        // 不影响取消退款结果，只记录错误
      }
      
      return { success: true, message: '已取消退款申请' }
    } catch (e) {
      console.error('取消退款异常:', e)
      return { success: false, message: '系统异常' }
    }
  }

  // 再次购买
  async rePurchase(order: any): Promise<boolean> {
      try {
          // 将 order 转换为 UTSJSONObject 以安全访问属性
          const orderObj = JSON.parse(JSON.stringify(order)) as UTSJSONObject
          // 尝试获取 ml_order_items 或 items
          let itemsKey = 'ml_order_items'
          let itemsRaw = orderObj.get(itemsKey)
          
          if (itemsRaw == null) {
              itemsKey = 'items'
              itemsRaw = orderObj.get(itemsKey)
          }
          
          if (itemsRaw == null) return false
          
          // 断言为数组
          const items = itemsRaw as any[]
          if (items.length === 0) return false

          // 简单的循环添加，实际项目中可以优化为批量插入
          for (let i = 0; i < items.length; i++) {
             // 同样，item 也是 UTSJSONObject 或支持访问的对象
             const item = JSON.parse(JSON.stringify(items[i])) as UTSJSONObject
             const productId = item.getString('product_id') 
             const skuId = item.getString('sku_id')
             // 数量可能是数字或字符串
             const quantity = item.getNumber('quantity') ?? 1
             
             if (productId != null) {
                await this.addToCart(productId, quantity, skuId ?? '', '')
             }
          }
          return true
      } catch (e) {
          console.error('rePurchase error', e)
          return false
      }
  }

  // 申请售后 (Legacy/Simple update)
  async applyRefund(orderId: string, reason: string): Promise<boolean> {
      try {
           // 更新订单状态为 退款中 (6)
           const response = await supa
             .from('ml_orders')
             .update({
                 order_status: 6,
                 cancel_reason: reason,
                 updated_at: new Date().toISOString()
             })
             .eq('id', orderId)
             .execute()
             
           return response.error === null
      } catch (e) {
          return false
      }
  }

  // 获取售后记录列表
  async getRefunds(statusList: number[] = [], page: number = 1, pageSize: number = 10): Promise<any[]> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              const empty: any[] = []
              return empty
          }

          let query = supa
            .from('ml_refunds')
            .select(`
                *,
                order:ml_orders!inner (
                    order_no,
                    created_at,
                    ml_order_items (
                        product_id,
                        product_name,
                        image_url
                    )
                )
            `)
            .eq('user_id', userId)
            .order('created_at', { ascending: false })

          if (statusList.length > 0) {
              // 显式转换为 any[] 以匹配 .in 方法的参数要求
              const anyList = statusList as any[]
              query = query.in('status', anyList)
          }

          query = query.range((page - 1) * pageSize, page * pageSize - 1)

          const response = await query.execute()

          if (response.error != null) {
              console.error('获取售后列表失败:', response.error)
              const empty: any[] = []
              return empty
          }

          const data = response.data
          if (data == null) {
              const empty: any[] = []
              return empty
          }

          return data
      } catch (e) {
          console.error('获取售后列表异常:', e)
          const empty: any[] = []
          return empty
      }
  }

  async deleteRefund(refundId: string): Promise<boolean> {
      try {
          const response = await supa
              .from('ml_refunds')
              .delete()
              .eq('id', refundId)
              .execute()

          if (response.error != null) {
              console.error('删除退款记录失败:', response.error)
              return false
          }

          return true
      } catch (e) {
          console.error('删除退款记录异常:', e)
          return false
      }
  }

  async getUserBalanceNumber(): Promise<number> {
      try {
          const userId = this.getCurrentUserId()
          console.log('[Supabase] getUserBalance userId:', userId)
          if (userId == null) return 0
          
          // 优先查 ml_user_wallets
          const walletRes = await supa
             .from('ml_user_wallets')
             .select('balance')
             .eq('user_id', userId!)
             .single()
             .execute()
          
          if (walletRes.error != null) {
              console.error('[Supabase] getUserBalance error:', walletRes.error)
          } else {
              console.log('[Supabase] getUserBalance data:', walletRes.data)
          }

          if (walletRes.error == null && walletRes.data != null) {
              let data = walletRes.data
              // 如果是数组，取第一项
              if (Array.isArray(data)) {
                  const arr = data as any[]
                if (arr.length == 0) {
                  data = null
                } else {
                  data = arr[0]
                }
              }

              if (data == null) {
                console.log('[Supabase] Wallet table returned empty array')
              } else {
                let val:number = 0
                if (data instanceof UTSJSONObject) {
                  val = data.getNumber('balance') ?? 0
                  // 尝试字符串转换，防止精度丢失导致转为string
                  if (val === 0 && data.getString('balance') != null) {
                      val = parseFloat(data.getString('balance')!)
                  }
                  return val
                } else if (data != null) {
                  // 对于 Map 或 loose object
                  const plainObj = JSON.parse(JSON.stringify(data))
                  const rawBalance = plainObj['balance']
                  if (typeof rawBalance === 'number') {
                    val = rawBalance as number
                  } else if (typeof rawBalance === 'string' && rawBalance != '') {
                    val = parseFloat(rawBalance as string)
                  }
                  return val
                }
              }
          }

          console.log('[Supabase] Wallet table empty, checking profile...')

          // Fallback to profile
          const profile = await this.getUserProfile()
          if (profile != null) {
              if (profile instanceof UTSJSONObject) {
                  return profile.getNumber('balance') ?? 0
              } else {
                  const pObj = JSON.parse(JSON.stringify(profile)) as UTSJSONObject
                  return pObj.getNumber('balance') ?? 0
              }
          }
          return 0
      } catch(e) {
          console.error('[Supabase] getUserBalance exception:', e)
          return 0
      }
  }
  
  // 获取用户积分
  async getUserPoints(): Promise<number> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return 0
          
          // 查 ml_user_points
          const res = await supa
             .from('ml_user_points')
             .select('points')
             .eq('user_id', userId!)
             .single()
             .execute()
             
          if (res.error != null) {
              console.error('[Supabase] getUserPoints error:', res.error)
          }

          if (res.error == null && res.data != null) {
             let data = res.data
             // 如果是数组，取第一项
             if (Array.isArray(data)) {
                  const arr = data as any[]
                if (arr.length == 0) {
                  data = null
                } else {
                  data = arr[0]
                }
             }

             if (data instanceof UTSJSONObject) {
                 return data.getNumber('points') ?? 0
             } else if (data != null) {
                 // 尝试转为 UTSJSONObject
               const plainObj = JSON.parse(JSON.stringify(data))
               const rawPoints = plainObj['points']
               if (typeof rawPoints === 'number') {
                 return rawPoints as number
               }
               if (typeof rawPoints === 'string' && rawPoints != '') {
                 return parseFloat(rawPoints as string)
               }

                 return 0
             }
          }
          
          // Fallback check profile if needed
          const profile = await this.getUserProfile()
          if (profile != null) {
               if (profile instanceof UTSJSONObject) {
                   return profile.getNumber('points') ?? 0
               } else {
                 const plainProfile = JSON.parse(JSON.stringify(profile))
                 const rawPoints = plainProfile['points']
                 if (typeof rawPoints === 'number') {
                   return rawPoints as number
                 }
                 if (typeof rawPoints === 'string' && rawPoints != '') {
                   return parseFloat(rawPoints as string)
                 }
                 return 0
               }
          }
          
          return 0
        } catch (e) {
          return 0
      }
  }

  // 获取钱包交易记录
  async getTransactions(page: number = 1, limit: number = 20): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
          const empty: any[] = []
          return empty
      }

      const from = (page - 1) * limit
      const to = from + limit - 1

      const response = await supa
        .from('ml_wallet_transactions')
        .select('*')
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .range(from, to)
        .execute()

      if (response.error != null) {
        console.error('获取交易记录失败:', response.error)
        const empty: any[] = []
        return empty
      }
      
      const data = response.data
      if (data == null) {
          const empty: any[] = []
          return empty
      }

      return data as any[]
    } catch (e) {
      console.error('获取交易记录异常:', e)
      const empty: any[] = []
      return empty
    }
  }
  
  // 获取积分记录
  async getPointRecords(): Promise<any[]> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              const empty: any[] = []
              return empty
          }
          
          const res = await supa
             .from('ml_point_records')
             .select('*')
             .eq('user_id', userId!)
             .order('created_at', { ascending: false })
             .execute()
             
          if (res.error != null) {
              const empty: any[] = []
              return empty
          }
          const data = res.data
          if (data == null) {
              const empty: any[] = []
              return empty
          }
          return data as any[]
      } catch (e) {
          const empty: any[] = []
          return empty
      }
  }

  // 获取用户红包
  async getUserRedPackets(): Promise<any[]> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              const empty: any[] = []
              return empty
          }

          const res = await supa
              .from('ml_user_red_packets')
              .select('*')
              .eq('user_id', userId!)
              .order('created_at', { ascending: false })
              .execute()

          if (res.error != null) {
              console.error('获取红包失败:', res.error)
              const empty: any[] = []
              return empty
          }
          const data = res.data
          if (data == null) {
              const empty: any[] = []
              return empty
          }
          return data as any[]
      } catch (e) {
          console.error('获取红包异常:', e)
          const empty: any[] = []
          return empty
      }
  }

  // 获取用户银行卡
  async getUserBankCards(): Promise<any[]> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              const empty: any[] = []
              return empty
          }

          const res = await supa
              .from('ml_user_bank_cards')
              .select('*')
              .eq('user_id', userId!)
              .order('created_at', { ascending: false })
              .execute()

          if (res.error != null) {
              console.error('获取银行卡失败:', res.error)
              const empty: any[] = []
              return empty
          }
          const data = res.data
          if (data == null) {
              const empty: any[] = []
              return empty
          }
          return data as any[]
      } catch (e) {
          console.error('获取银行卡异常:', e)
          const empty: any[] = []
          return empty
      }
  }

  // 余额充值 (调用 RPC)
  async rechargeBalance(amount: number): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false
          
          const res = await supa.rpc('recharge_wallet', { 
              p_user_id: userId,
              p_amount: amount 
          })
          
          if (res.error != null) {
              console.error('充值失败RPC:', res.error)
              return false
          }
           
          // 简单判断: 如果没有error且data里success为true
          const data = res.data
          if (data instanceof UTSJSONObject) {
               return data.getBoolean('success') ?? false
          }
          // 如果返回不是对象，作为失败处理
          return false
      } catch (e) {
          console.error('充值异常:', e)
          return false
      }
  }

  // 余额提现 (调用 RPC)
  async withdrawBalance(amount: number): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false
          
          const res = await supa.rpc('withdraw_wallet', { 
              p_user_id: userId,
              p_amount: amount 
          })
          
          if (res.error != null) {
              console.error('提现失败RPC:', res.error)
              return false
          }
          
          const data = res.data
          if (data instanceof UTSJSONObject) {
               return data.getBoolean('success') ?? false
          }
          return false
      } catch (e) {
          console.error('提现异常:', e)
          return false
      }
  }

  // 添加银行卡
  async addBankCard(card: UTSJSONObject): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false
          
          // 补全 user_id
          card.set('user_id', userId)
          
          const res = await supa
             .from('ml_user_bank_cards')
             .insert(card)
             .execute()
          
          if (res.error != null) {
              console.error('添加银行卡失败:', res.error)
              return false
          }
          return true
      } catch (e) {
          console.error('添加银行卡异常:', e)
          return false
      }
  }
  
  // 删除银行卡
  async deleteBankCard(cardId: string): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false
          
          const res = await supa
              .from('ml_user_bank_cards')
              .eq('id', cardId)
              .eq('user_id', userId!)
              .delete()
              .execute()
              
          if (res.error != null) {
               console.error('删除银行卡失败:', res.error)
               return false
          }
          return true
      } catch (e) {
           console.error('删除银行卡异常:', e)
           return false
      }
  }

  // 收藏相关
  async checkFavorite(productId: string): Promise<boolean> {
     try {
         const userId = this.getCurrentUserId()
         console.log(`[CheckFav] Checking for User: ${userId}, Product: ${productId}`)
         
         if (userId == null) return false
         
         const response = await supa
            .from('ml_user_favorites')
            .select('*') // Select all to verify data
            .eq('user_id', userId!)
            .eq('target_id', productId)
            .eq('target_type', '1') // 使用字符串 '1'
            .limit(1)
            .execute()
         
         // console.log(`[CheckFav] Response: ${JSON.stringify(response)}`)
         
         if (response.error != null) {
             console.error(`[CheckFav] Error: ${JSON.stringify(response.error)}`)
             return false
         }
         
         const data = response.data
         if (Array.isArray(data)) {
             if ((data as any[]).length > 0) {
                 // Double check: ensure the returned item actually matches the product ID
                 // This guards against potential query filter failures
                 const item = data[0]
                 let targetId = ''
                 if (item instanceof UTSJSONObject) {
                     targetId = item.getString('target_id') ?? ''
                 } else {
                     const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
                     targetId = itemObj.getString('target_id') ?? ''
                 }
                 
                 if (targetId != '' && targetId != productId) {
                     console.error(`[CheckFav] ID Mismatch! Query ${productId}, Got ${targetId}`)
                     return false
                 }
                 
                 return true
             }
         } else if (data instanceof UTSJSONObject) {
             // Handle single object return case (though limit(1) usually returns array)
             let targetId = data.getString('target_id') ?? ''
             if (targetId !== '' && targetId !== productId) {
                 return false
             }
             return true
         }
            
         return false
     } catch(e) {
         console.error(`[CheckFav] Exception: ${e}`)
         return false
     }
  }
  
  async toggleFavorite(productId: string): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) return false
          
          console.log(`[ToggleFav] Toggling for ${productId}`)
          
          // Check if exists
          const exists = await this.checkFavorite(productId)
          console.log(`[ToggleFav] Current status: ${exists}`)
          
          if (exists) {
              const response = await supa
                .from('ml_user_favorites')
                .eq('user_id', userId!)
                .eq('target_id', productId)
                .eq('target_type', '1')
                .delete()
                .execute()
                
              if (response.error != null) {
                  console.error('取消收藏失败:', response.error)
                  return true // 仍然是收藏状态
              }
              return false // 已取消收藏
          } else {
              const response = await supa
                .from('ml_user_favorites')
                .insert({
                    user_id: userId,
                    target_id: productId,
                    target_type: '1',
                    created_at: new Date().toISOString()
                })
                .execute()
                
              if (response.error != null) {
                  console.error('添加收藏失败:', response.error)
                  return false // 添加失败，仍未收藏
              }
              return true // 已收藏
          }
      } catch (e) {
          console.error('切换收藏状态异常:', e)
          // 发生异常时，尝试查询当前状态返回
          return await this.checkFavorite(productId)
      }
  }
  
  async getFavorites(): Promise<any[]> {
     try {
         const userId = this.getCurrentUserId()
         if (userId == null) {
             const empty: any[] = []
             return empty
         }
         
         // 第一步：查询收藏列表
         const response = await supa
            .from('ml_user_favorites')
            .select('*')
            .eq('user_id', userId!)
            .eq('target_type', '1')
            .order('created_at', { ascending: false })
            .execute()
            
         if (response.error != null) {
            const empty: any[] = []
            return empty
         }
         const favorites = response.data as any[]
         if (favorites == null || favorites.length === 0) {
            const empty: any[] = []
            return empty
         }
         
         // 第二步：收集商品ID
         const productIds: string[] = []
         for (let i = 0; i < favorites.length; i++) {
             let item: any = favorites[i]
             let itemObj: UTSJSONObject
             if (item instanceof UTSJSONObject) {
                 itemObj = item as UTSJSONObject
             } else {
                 itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
             }
             
             // target_id 可能是 Integer 或 String 类型，需要安全转换
             const targetIdRaw = itemObj.get('target_id')
             let pid = ''
             if (targetIdRaw != null) {
                 if (typeof targetIdRaw === 'string') {
                     pid = targetIdRaw as string
                 } else if (typeof targetIdRaw === 'number') {
                     pid = (targetIdRaw as number).toString()
                 }
             }
             if (pid !== '') productIds.push(pid)
         }
         
         if (productIds.length === 0) return []
         
         // 第三步：批量查询商品详情
         const anyProductIds = productIds as any[]
         const productRes = await supa
            .from('ml_products')
            .select('id, name, main_image_url, base_price, sale_count')
            .in('id', anyProductIds)
            .execute()
            
         if (productRes.error != null) {
             const empty: any[] = []
             return empty
         }
         const products = productRes.data as any[]
         const productMap = new Map<string, any>()
         
         for (let i = 0; i < products.length; i++) {
             // 显式声明类型为 any
             let p: any = products[i]
             let pid = ''
             if (p instanceof UTSJSONObject) {
                 pid = p.getString('id') ?? ''
             } else {
                 const pObj = JSON.parse(JSON.stringify(p)) as UTSJSONObject
                 pid = pObj.getString('id') ?? ''
             }
             if (pid !== '') productMap.set(pid, p)
         }
         
         // 第四步：组合数据
         const result: any[] = []
         for (let i = 0; i < favorites.length; i++) {
             let item: any = favorites[i]
             let newItem: UTSJSONObject
             
             if (item instanceof UTSJSONObject) {
                 newItem = JSON.parse(JSON.stringify(item)) as UTSJSONObject
             } else {
                 newItem = JSON.parse(JSON.stringify(item)) as UTSJSONObject
             }
             
             // target_id 可能是 Integer 或 String 类型，需要安全转换
             const targetIdRaw = newItem.get('target_id')
             let targetId = ''
             if (targetIdRaw != null) {
                 if (typeof targetIdRaw === 'string') {
                     targetId = targetIdRaw as string
                 } else if (typeof targetIdRaw === 'number') {
                     targetId = (targetIdRaw as number).toString()
                 }
             }
             
             if (targetId !== '') {
                 const product = productMap.get(targetId)
                 if (product != null) {
                     newItem.set('ml_products', product)
                     result.push(newItem)
                 }
             }
         }
         
         return result
     } catch (e) {
         console.error('获取收藏列表异常:', e)
         return []
     }
  }

  // 获取足迹列表
  async getFootprints(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
          console.log('[getFootprints] 用户未登录')
          const empty: any[] = []
          return empty
      }

      console.log('[getFootprints] 查询足迹, userId:', userId)

      // 1. 获取足迹记录
      const response = await supa
        .from('ml_user_footprints')
        .select('*')
        .eq('user_id', userId!)
        .order('updated_at', { ascending: false })
        .limit(50)
        .execute()

      console.log('[getFootprints] 足迹查询 error:', response.error)
      console.log('[getFootprints] 足迹查询 data:', JSON.stringify(response.data))

      if (response.error != null) {
        console.error('[getFootprints] 获取足迹失败:', response.error)
        const empty: any[] = []
        return empty
      }

      const footprints = response.data as any[]
      if (footprints == null || footprints.length === 0) {
          console.log('[getFootprints] 没有足迹记录')
          const empty: any[] = []
          return empty
      }

      console.log('[getFootprints] 足迹记录数量:', footprints.length)

      // 2. 收集商品ID
      const productIds: string[] = []
      for (let i = 0; i < footprints.length; i++) {
          let item = footprints[i]
          let pid = ''
          if (item instanceof UTSJSONObject) {
              pid = item.getString('product_id') ?? ''
          } else {
              const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
              pid = itemObj.getString('product_id') ?? ''
          }
          if (pid !== '' && !productIds.includes(pid)) productIds.push(pid)
      }

      if (productIds.length === 0) return []
      
      const productIdsAny: any[] = []
      for(let i=0; i<productIds.length; i++) {
          productIdsAny.push(productIds[i])
      }

      // 3. 批量查询商品详情
      const productRes = await supa
        .from('ml_products_detail_view')
        .select('id, name, main_image_url, base_price, market_price, sale_count, merchant_id, shop_name')
        .in('id', productIdsAny)
        .execute()

      // 如果视图失败，回退查基础表
      let products: any[] = []
      if (productRes.error == null && productRes.data != null) {
          products = productRes.data as any[]
      } else {
          console.warn('View查询失败，尝试查询基础表')
          const baseRes = await supa
             .from('ml_products')
             .select('id, name, main_image_url, base_price, market_price, sale_count, merchant_id')
             .in('id', productIdsAny)
             .execute()
          if (baseRes.error == null) {
              products = baseRes.data as any[]
          }
      }

      const productMap = new Map<string, any>()
      for(let i=0; i<products.length; i++) {
          let p = products[i]
          let pid = ''
          if (p instanceof UTSJSONObject) {
              pid = p.getString('id') ?? ''
          } else {
              const pObj = JSON.parse(JSON.stringify(p)) as UTSJSONObject
              pid = pObj.getString('id') ?? ''
          }
          if (pid !== '') productMap.set(pid, p)
      }

      // 4. 组合结果
      const result: any[] = []
      for (let i = 0; i < footprints.length; i++) {
        let fp = footprints[i]
        let pid = ''
        let viewTime = 0
        
        if (fp instanceof UTSJSONObject) {
             pid = fp.getString('product_id') ?? ''
             const dateStr = fp.getString('updated_at')
             if (dateStr != null) viewTime = new Date(dateStr).getTime()
        } else {
             const fpObj = JSON.parse(JSON.stringify(fp)) as UTSJSONObject
             pid = fpObj.getString('product_id') ?? ''
             const dateStr = fpObj.getString('updated_at')
             if (dateStr != null) viewTime = new Date(dateStr).getTime()
        }

        const product = productMap.get(pid)
        if (product != null) {
            let pName = ''
            let pImage = ''
            let pPrice = 0
            let pOriginalPrice = 0
            let pSales = 0
            let pShopId = ''
            let pShopName = ''
            
            if (product instanceof UTSJSONObject) {
                pName = product.getString('name') ?? ''
                pImage = product.getString('main_image_url') ?? ''
                pPrice = product.getNumber('base_price') ?? 0
                pOriginalPrice = product.getNumber('market_price') ?? 0
                pSales = product.getNumber('sale_count') ?? 0
                pShopId = product.getString('merchant_id') ?? ''
                pShopName = product.getString('shop_name') ?? ''
            } else {
                const pObj = JSON.parse(JSON.stringify(product)) as UTSJSONObject
                pName = pObj.getString('name') ?? ''
                pImage = pObj.getString('main_image_url') ?? ''
                pPrice = pObj.getNumber('base_price') ?? 0
                pOriginalPrice = pObj.getNumber('market_price') ?? 0
                pSales = pObj.getNumber('sale_count') ?? 0
                pShopId = pObj.getString('merchant_id') ?? ''
                pShopName = pObj.getString('shop_name') ?? ''
            }

            const fpObj = new UTSJSONObject()
            fpObj.set('id', pid)
            fpObj.set('name', pName)
            fpObj.set('price', pPrice)
            fpObj.set('original_price', pOriginalPrice)
            fpObj.set('image', pImage)
            fpObj.set('sales', pSales)
            fpObj.set('shopId', pShopId)
            fpObj.set('shopName', pShopName)
            fpObj.set('merchant_id', pShopId)
            fpObj.set('viewTime', viewTime)
            result.push(fpObj)
        }
      }
      
      return result
    } catch (error) {
      console.error('获取足迹异常:', error)
      return []
    }
  }

  // 添加/更新足迹
  async addFootprint(productId: string): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
            console.log('[addFootprint] 用户未登录')
            return false
          }
          
          console.log('[addFootprint] 添加足迹, userId:', userId, 'productId:', productId)
          
          // 检查是否已存在
          const checkRes = await supa
             .from('ml_user_footprints')
             .select('id')
             .eq('user_id', userId!)
             .eq('product_id', productId)
             .execute()
          
          console.log('[addFootprint] 检查结果 error:', checkRes.error)
          console.log('[addFootprint] 检查结果 data:', JSON.stringify(checkRes.data))

          const checkData = checkRes.data as any[]
          const exists = checkData != null && Array.isArray(checkData) && checkData.length > 0
          
          if (checkRes.error == null && exists) {
              console.log('[addFootprint] 足迹已存在，更新时间')
              // 更新时间
              const updateRes = await supa
                 .from('ml_user_footprints')
                 .update({ updated_at: new Date().toISOString() })
                 .eq('user_id', userId!)
                 .eq('product_id', productId)
                 .execute()
              console.log('[addFootprint] 更新结果 error:', updateRes.error)
          } else {
              console.log('[addFootprint] 足迹不存在，插入新记录')
              // 插入新记录
              const insertPayload = new UTSJSONObject()
              insertPayload.set('user_id', userId!)
              insertPayload.set('product_id', productId)
              insertPayload.set('created_at', new Date().toISOString())
              insertPayload.set('updated_at', new Date().toISOString())
              
              const insertRes = await supa
                 .from('ml_user_footprints')
                 .insert(insertPayload)
                 .execute()
              console.log('[addFootprint] 插入结果 error:', insertRes.error)
          }
          return true
      } catch (e) {
          console.error('[addFootprint] 添加足迹异常:', e)
          return false
      }
  }

  // 删除单个足迹
  async deleteFootprint(productId: string): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              console.log('[deleteFootprint] 用户未登录')
              return false
          }

          const response = await supa
              .from('ml_user_footprints')
              .eq('user_id', userId)
              .eq('product_id', productId)
              .delete()
              .execute()

          if (response.error != null) {
              console.error('[deleteFootprint] 删除足迹失败:', response.error)
              return false
          }

          console.log('[deleteFootprint] 删除足迹成功')
          return true
      } catch (e) {
          console.error('[deleteFootprint] 删除足迹异常:', e)
          return false
      }
  }

  // 批量删除足迹
  async deleteFootprints(productIds: string[]): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              console.log('[deleteFootprints] 用户未登录')
              return false
          }

          const idsAny: any[] = []
          for (let i = 0; i < productIds.length; i++) {
              idsAny.push(productIds[i])
          }

          const response = await supa
              .from('ml_user_footprints')
              .eq('user_id', userId)
              .in('product_id', idsAny)
              .delete()
              .execute()

          if (response.error != null) {
              console.error('[deleteFootprints] 批量删除足迹失败:', response.error)
              return false
          }

          console.log('[deleteFootprints] 批量删除足迹成功')
          return true
      } catch (e) {
          console.error('[deleteFootprints] 批量删除足迹异常:', e)
          return false
      }
  }

  // 清空所有足迹
  async clearFootprints(): Promise<boolean> {
      try {
          const userId = this.getCurrentUserId()
          if (userId == null) {
              console.log('[clearFootprints] 用户未登录')
              return false
          }

          const response = await supa
              .from('ml_user_footprints')
              .eq('user_id', userId)
              .delete()
              .execute()

          if (response.error != null) {
              console.error('[clearFootprints] 清空足迹失败:', response.error)
              return false
          }

          console.log('[clearFootprints] 清空足迹成功')
          return true
      } catch (e) {
          console.error('[clearFootprints] 清空足迹异常:', e)
          return false
      }
  }

  async getAddressList(): Promise<UserAddress[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
          const empty: UserAddress[] = []
          return empty
      }

      const response = await supa
        .from('ml_user_addresses')
        .select('*, recipient_name:receiver_name, phone:receiver_phone, detail_address:address_detail')
        .eq('user_id', userId!)
        .order('is_default', { ascending: false })
        .order('created_at', { ascending: false })
        .execute()

      if (response.error != null) {
        console.error('获取地址列表失败:', response.error)
        const empty: UserAddress[] = []
        return empty
      }
      return response.data as UserAddress[]
    } catch (e) {
      console.error('获取地址列表异常:', e)
      const empty: UserAddress[] = []
      return empty
    }
  }

  // 设置默认地址
  async setDefaultAddress(addressId: string): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        console.error('用户未登录，无法设置默认地址')
        return false
      }

      // 先取消所有默认地址
      await this.clearDefaultAddress(userId!)

      // 设置新的默认地址
      const response = await supa
        .from('ml_user_addresses')
        .update({
          is_default: true,
          updated_at: new Date().toISOString()
        })
        .eq('id', addressId)
        .eq('user_id', userId!)
        .execute()

      if (response.error != null) {
        console.error('设置默认地址失败:', response.error)
        return false
      }

      return true
    } catch (error) {
      console.error('设置默认地址异常:', error)
      return false
    }
  }

  // 获取用户优惠券列表
  async getUserCoupons(status: number = 1): Promise<UserCoupon[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
          const empty: UserCoupon[] = []
          return empty
      }

      // 假设有一个视图或者直接关联 ml_user_coupons 和 ml_coupon_templates
      // 这里简化处理，尝试直接从 ml_user_coupons 读取，并且加入 template 信息
      // 如果没有 view，可能需要改为两个查询或者使用 left join
      const response = await supa
        .from('ml_user_coupons')
        .select('*, template:ml_coupon_templates(name, amount, min_spend)')
        .eq('user_id', userId!)
        .eq('status', status.toString())
        .order('expire_at', { ascending: true })
        .execute()

      if (response.error != null) {
        console.error('获取优惠券失败:', response.error)
        const empty: UserCoupon[] = []
        return empty
      }

      // 安全处理返回数据 - 安卓端可能是 UTSJSONObject 或 UTSArray
      const rawData: any[] = []
      const respData = response.data
      console.log('[getUserCoupons] 原始数据类型:', typeof respData, '是否数组:', Array.isArray(respData))
      if (respData != null) {
        if (Array.isArray(respData)) {
          const arr = respData as any[]
          console.log('[getUserCoupons] 数组长度:', arr.length)
          for (let i = 0; i < arr.length; i++) {
            rawData.push(arr[i])
          }
        } else if (respData instanceof UTSJSONObject) {
          // 单个对象情况，包装成数组
          console.log('[getUserCoupons] 单个对象，包装成数组')
          rawData.push(respData)
        } else {
          // 尝试 JSON 转换
          try {
            const parsed = JSON.parse(JSON.stringify(respData))
            console.log('[getUserCoupons] JSON转换后是否数组:', Array.isArray(parsed))
            if (Array.isArray(parsed)) {
              console.log('[getUserCoupons] 转换后数组长度:', parsed.length)
              for (let i = 0; i < parsed.length; i++) {
                rawData.push(parsed[i])
              }
            }
          } catch (parseErr) {
            console.error('解析优惠券数据异常:', parseErr)
          }
        }
      }
      console.log('[getUserCoupons] 最终rawData长度:', rawData.length)

      // 映射数据，将 template 的字段展平
      const coupons: UserCoupon[] = []
      for (let i = 0; i < rawData.length; i++) {
          const item = rawData[i]
          let template: any | null = null
          let itemId = ''
          let itemUserId = ''
          let itemTmplId = ''
          let itemCode = ''
          let itemStatus = 0
          let itemRecv = ''
          let itemExpire = ''
          
          if (item instanceof UTSJSONObject) {
             template = item.get('template') as any | null
             itemId = item.getString('id') ?? ''
             itemUserId = item.getString('user_id') ?? ''
             itemTmplId = item.getString('template_id') ?? ''
             itemCode = item.getString('coupon_code') ?? ''
             itemStatus = item.getNumber('status') ?? 0
             itemRecv = item.getString('received_at') ?? ''
             itemExpire = item.getString('expire_at') ?? ''
          } else {
             const iObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
             template = iObj.get('template') as any | null
             itemId = iObj.getString('id') ?? ''
             itemUserId = iObj.getString('user_id') ?? ''
             itemTmplId = iObj.getString('template_id') ?? ''
             itemCode = iObj.getString('coupon_code') ?? ''
             itemStatus = iObj.getNumber('status') ?? 0
             itemRecv = iObj.getString('received_at') ?? ''
             itemExpire = iObj.getString('expire_at') ?? ''
          }
          
          if (template == null) template = new UTSJSONObject()
          
          let tName = ''
          let tAmount = 0
          let tMin = 0
          
          if (template instanceof UTSJSONObject) {
              tName = template.getString('name') ?? '优惠券'
              tAmount = template.getNumber('amount') ?? 0
              tMin = template.getNumber('min_spend') ?? 0
          } else {
             const tObj = JSON.parse(JSON.stringify(template)) as UTSJSONObject
             tName = tObj.getString('name') ?? '优惠券'
             tAmount = tObj.getNumber('amount') ?? 0
             tMin = tObj.getNumber('min_spend') ?? 0
          }

          // 创建真正的 UserCoupon 对象，而不是 UTSJSONObject
          const couponItem: UserCoupon = {
            id: itemId,
            user_id: itemUserId,
            template_id: itemTmplId,
            coupon_code: itemCode,
            status: itemStatus,
            received_at: itemRecv,
            expire_at: itemExpire,
            template_name: tName,
            amount: tAmount,
            min_spend: tMin
          }
          
          coupons.push(couponItem)
      }

      return coupons
    } catch (e) {
        console.error('获取优惠券异常:', e)
        const empty: UserCoupon[] = []
        return empty
    }
  }

  // 获取可用优惠券数量
  async getUserCouponCount(): Promise<number> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return 0

      const response = await supa
        .from('ml_user_coupons')
        .select('id', { count: 'exact' })
        .eq('user_id', userId!)
        .eq('status', '1')
        .gt('expire_at', new Date().toISOString())
        .limit(1)
        .execute()

      if (response.error != null) {
          return 0
      }
      return response.total ?? 0
    } catch (e) {
        return 0
    }
  }

  // 获取店铺/商品可用优惠券
  async getAvailableCoupons(merchantId: string): Promise<any[]> {
    return this.fetchShopCoupons(merchantId)
  }

  // ALIAS for Cache busting: 获取店铺优惠券
  async fetchShopCoupons(merchantId: string): Promise<any[]> {
    try {
      console.log('[fetchShopCoupons] 开始获取优惠券，merchantId:', merchantId)
      // 查询该商家的优惠券 + 平台通用券 (merchant_id is null)
      // 注意：这里简化逻辑，实际可能需要联合查询用户是否已领取
      const response = await supa
        .from('ml_coupon_templates')
        .select('*')
        .or(`merchant_id.eq.${merchantId},merchant_id.is.null`)
        .eq('status', '1')  // 使用字符串 '1'
        .gt('end_time', new Date().toISOString())
        .order('discount_value', { ascending: false })
        .execute()
      
      if (response.error != null) {
        console.error('Fetch coupons failed:', response.error)
        const empty: any[] = []
        return empty
      }
      
      const data = response.data
      if (data == null) {
          const empty: any[] = []
          return empty
      }
      console.log('[fetchShopCoupons] 获取到优惠券数量:', (data as any[]).length)
      return data as any[]
    } catch (e) {
      console.error('Fetch coupons error:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 领取优惠券
  async claimCoupon(templateId: string, userId: string): Promise<boolean> {
     return this.claimShopCoupon(templateId, userId)
  }

  // ALIAS for Cache busting
  async claimShopCoupon(templateId: string, userId: string): Promise<boolean> {
     try {
       console.log('Claiming coupon templateId:', templateId, 'userId:', userId)

       // 1. Fetch template details to get merchant_id and validity
       const tmplRes = await supa
         .from('ml_coupon_templates')
         .select('*')
         .eq('id', templateId)
         .limit(1)
         .execute()
       
       if (tmplRes.error != null) {
         console.error('Claim Coupon: Template query error', tmplRes.error)
         return false
       }

       // Null check for data
       if (tmplRes.data == null) {
           console.error('Claim Coupon: Template data response is null')
           return false
       }
       
       const dataList = tmplRes.data as any[]
       if (dataList.length === 0) {
           console.error('Claim Coupon: Template not found (empty list)')
           return false
       }

       const template = dataList[0]
       
       // Safe property access
       let validDays = 0
       let endTimeStr: string | null = null
       let merchantId: string | null = null
       
       if (template instanceof UTSJSONObject) {
           validDays = template.getNumber('valid_days') ?? 0
           endTimeStr = template.getString('end_time')
           merchantId = template.getString('merchant_id')
       } else {
           const tJson = JSON.parse(JSON.stringify(template)) as UTSJSONObject
           validDays = tJson.getNumber('valid_days') ?? 0
           endTimeStr = tJson.getString('end_time')
           merchantId = tJson.getString('merchant_id')
       }
       
       // Calculate expire_at
       let expireAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString()
       if (validDays > 0) {
           expireAt = new Date(Date.now() + (validDays * 24 * 60 * 60 * 1000)).toISOString()
       } else if (endTimeStr != null && endTimeStr !== '') {
           expireAt = endTimeStr
       }
       
       // Handle UUID fields: Empty string is not valid UUID, must be null
       if (merchantId != null && merchantId.length === 0) {
          merchantId = null
       }

       // 2. Insert into user coupons with merchant_id
       const insertData = {
            user_id: userId,
            template_id: templateId,
            merchant_id: merchantId, // Important for shop filtering: null for platform coupons
            coupon_code: 'C' + Date.now() + Math.floor(Math.random() * 1000), 
            status: 1, 
            expire_at: expireAt,
            received_at: new Date().toISOString()
       }
       
       console.log('Claim Coupon Insert Payload:', JSON.stringify(insertData))

       const response = await supa
         .from('ml_user_coupons')
         .insert(insertData)
         .execute()
        
        if (response.error != null) {
            console.error('Claim Coupon: Insert failed:', JSON.stringify(response.error))
            // 尝试降级：如果 merchant_id 报错，尝试不带 merchant_id (仅调试用，或兼容旧表结构)
            if (JSON.stringify(response.error).includes('merchant_id')) {
                 console.log('Retrying without merchant_id...')
                 const fallbackData = {
                    user_id: userId,
                    template_id: templateId,
                    coupon_code: 'C' + Date.now() + Math.random().toString().substring(2,6),
                    status: 1,
                    expire_at: expireAt,
                    received_at: new Date().toISOString()
                 }
                 const res2 = await supa.from('ml_user_coupons').insert(fallbackData).execute()
                 if (res2.error == null) return true
            }
            return false
        }
        return true
     } catch(e) {
        console.error('Claim coupon error:', e)
        return false
     }
  }

  // ==========================================
  // 聊天相关方法
  // ==========================================

  // 发送消息
  async sendMessage(merchantId: string, content: string, msgType: string = 'text'): Promise<boolean> {
      // 确保 session 有效
      const userId = this.getCurrentUserId()
      if (userId == null) {
          console.error("sendMessage failed: user not logged in or session lost")
          return false
      }

      try {
          // Debug check
          // const session = supa.getSession()
          // console.log("Sending check: UserID", userId, "AuthID:", session.user?.getString('id'))
          
          const msg = {
              sender_id: userId!,
              receiver_id: merchantId,
              content: content,
              msg_type: msgType,
              is_read: false,
              is_from_user: true
          }
          
          const response = await supa
            .from('ml_chat_messages')
            .insert(msg)
            .execute()
            
          if (response.error != null) {
              console.error('sendMessage error:', response.error)
              return false
          }
          return true
      } catch (e) {
          console.error('sendMessage exception:', e)
          return false
      }
  }
  
  // 上传聊天图片
  async uploadChatImage(filePath: string): Promise<string> {
      const userId = this.getCurrentUserId()
      if (userId == null) {
          console.error("uploadChatImage failed: user not logged in")
          return ''
      }
      
      try {
          // 生成唯一文件名
          const timestamp = Date.now()
          const randomStr = Math.random().toString(36).substring(2, 8)
          const fileName = `chat_${userId}_${timestamp}_${randomStr}.jpg`
          const storagePath = `chat-images/${fileName}`
          
          console.log('[uploadChatImage] 开始上传:', filePath, '->', storagePath)
          
          const response = await supa.storage
            .from('chat')
            .upload(storagePath, filePath, {})
          
          if (response.error != null) {
              console.error('[uploadChatImage] 上传失败:', response.error)
              return ''
          }
          
          // 构建公开访问URL
          const publicUrl = `${supa.baseUrl}/storage/v1/object/public/chat/${storagePath}`
          console.log('[uploadChatImage] 上传成功:', publicUrl)
          return publicUrl
      } catch (e) {
          console.error('[uploadChatImage] 上传异常:', e)
          return ''
      }
  }
  
  // 标记会话已读
  async markRead(merchantId: string): Promise<boolean> {
      const userId = this.getCurrentUserId()
      if (userId == null) return false
      try {
          const response = await supa
            .from('ml_chat_messages')
            .update({ is_read: true })
            .eq('sender_id', merchantId)
            .eq('receiver_id', userId)
            .eq('is_read', false)
            .execute() 

           if (response.error != null) return false
      } catch (e) { return false }
      return true
  }

  // 提交商品评价
  async submitProductReviews(reviews: Array<UTSJSONObject>): Promise<boolean> {
      try {
          for (let i: number = 0; i < reviews.length; i++) {
              const review = reviews[i]
              const response = await supa
                .from('ml_product_reviews')
                .insert(review)
                .execute() 
              if (response.error != null) {
                  console.error('提交商品评价失败:', response.error)
                  return false
              }
          }
          return true
      } catch (e) { 
          console.error('提交商品评价失败:', e)
          return false 
      }
  }

  // 提交店铺评价
  async submitShopReview(review: UTSJSONObject): Promise<boolean> {
      try {
          const response = await supa
            .from('ml_shop_reviews')
            .insert(review)
            .execute() 
          return response.error == null
      } catch (e) { 
          console.error('提交店铺评价失败:', e)
          return false 
      }
  }

  // 更新订单状态
  async updateOrderStatus(orderId: string, status: number): Promise<boolean> {
      try {
          const updateData = new UTSJSONObject()
          updateData.set('order_status', status)
          const response = await supa
            .from('ml_orders')
            .update(updateData) 
            .eq('id', orderId)
            .execute() 
          return response.error == null
      } catch (e) { 
          console.error('更新订单状态失败:', e)
          return false 
      }
  }

  // ==================== 智能推荐相关API ====================

  // 获取热搜词（全站搜索频率最高的关键词）
  async getHotKeywords(limit: number = 10): Promise<string[]> {
    try {
      if (!logConsumerQueryStart('getHotKeywords', 'ml_search_history', 'keyword')) {
        return [] as string[]
      }
      const response = await supa
        .from('ml_search_history')
        .select('keyword')
        .order('created_at', { ascending: false })
        .limit(100)
        .execute()
      
      if (response.error != null || response.data == null) {
        logConsumerQueryFailure('getHotKeywords', 'ml_search_history', response.error)
        return [] as string[]
      }
      
      // 统计关键词频率
      const keywordCount = new Map<string, number>()
      const rawList = response.data as any[]
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        const keyword = safeGetString(itemObj, 'keyword').toLowerCase().trim()
        if (keyword.length > 0) {
          const count = keywordCount.get(keyword) ?? 0
          keywordCount.set(keyword, count + 1)
        }
      }
      
      // 按频率排序并返回前N个 - UTS兼容方式
      // 将Map转换为数组进行排序
      type KeywordEntry = {
        keyword: string
        count: number
      }
      const entryArray: KeywordEntry[] = []
      
      // 使用forEach遍历Map（UTS支持）
      keywordCount.forEach((value: number, key: string) => {
        entryArray.push({
          keyword: key,
          count: value
        })
      })
      
      // 按count降序排序
      entryArray.sort((a: KeywordEntry, b: KeywordEntry): number => {
        return b.count - a.count
      })
      
      // 取前limit个并提取关键词
      const sortedKeywords: string[] = []
      const maxCount = Math.min(entryArray.length, limit)
      for (let i = 0; i < maxCount; i++) {
        sortedKeywords.push(entryArray[i].keyword)
      }
      
      logConsumerQuerySuccess('getHotKeywords', 'ml_search_history', sortedKeywords.length)
      return sortedKeywords
    } catch (e) {
      logConsumerQueryFailure('getHotKeywords', 'ml_search_history', e)
      console.error('获取热搜词失败:', e)
      return [] as string[]
    }
  }

  // 获取用户搜索历史
  async getUserSearchHistory(limit: number = 10): Promise<string[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        return [] as string[]
      }
      
      const response = await supa
        .from('ml_search_history')
        .select('keyword')
        .order('created_at', { ascending: false })
        .limit(limit * 2)
        .execute()
      
      if (response.error != null || response.data == null) {
        return [] as string[]
      }
      
      const keywords: string[] = []
      const rawList = response.data as any[]
      const seen = new Set<string>()
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        const rawUserId = itemObj.get('user_id')
        const itemUserId = (typeof rawUserId == 'string') ? (rawUserId as string) : ''
        
        // 只获取当前用户的搜索历史
        if (itemUserId !== userId) continue
        
        const keyword = safeGetString(itemObj, 'keyword').trim()
        if (keyword.length > 0 && !seen.has(keyword)) {
          keywords.push(keyword)
          seen.add(keyword)
          if (keywords.length >= limit) break
        }
      }
      
      return keywords
    } catch (e) {
      console.error('获取用户搜索历史失败:', e)
      return [] as string[]
    }
  }

  // 获取用户浏览历史中的商品分类
  async getUserBrowseCategories(limit: number = 5): Promise<string[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        return [] as string[]
      }
      
      const response = await supa
        .from('ml_browse_history')
        .select('product_id')
        .order('created_at', { ascending: false })
        .limit(20)
        .execute()
      
      if (response.error != null || response.data == null) {
        return [] as string[]
      }
      
      // 获取浏览过的商品ID
      const productIds: string[] = []
      const rawList = response.data as any[]
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        // 手动过滤 user_id
        const rawUserId = itemObj.get('user_id')
        const itemUserId = (typeof rawUserId == 'string') ? (rawUserId as string) : ''
        if (itemUserId !== userId) continue
        
        const productId = safeGetString(itemObj, 'product_id')
        if (productId.length > 0) {
          productIds.push(productId)
        }
      }
      
      if (productIds.length === 0) {
        return [] as string[]
      }
      
      // 查询这些商品的分类
      const prodResponse = await supa
        .from('ml_products_detail_view')
        .select('id, category_id')
        .limit(50)
        .execute()
      
      if (prodResponse.error != null || prodResponse.data == null) {
        return [] as string[]
      }
      
      const categoryIds: string[] = []
      const prodList = prodResponse.data as any[]
      for (let i = 0; i < prodList.length; i++) {
        const prodItem = prodList[i]
        const prodObj = JSON.parse(JSON.stringify(prodItem)) as UTSJSONObject
        const prodId = safeGetString(prodObj, 'id')
        
        // 只统计浏览过的商品
        let found = false
        for (let j = 0; j < productIds.length; j++) {
          if (productIds[j] == prodId) {
            found = true
            break
          }
        }
        if (!found) continue
        
        const catId = safeGetString(prodObj, 'category_id')
        if (catId.length > 0 && categoryIds.indexOf(catId) < 0) {
          categoryIds.push(catId)
          if (categoryIds.length >= limit) break
        }
      }
      
      return categoryIds
    } catch (e) {
      console.error('获取用户浏览分类失败:', e)
      return [] as string[]
    }
  }

  // 智能推荐：综合用户搜索历史、浏览历史、热销商品
  async getSmartRecommendations(page: number = 1, limit: number = 10): Promise<PaginatedResponse<Product>> {
    try {
      if (!logConsumerQueryStart('getSmartRecommendations', 'ml_products_detail_view', 'composed: search_history + browse_history + products_detail_view')) {
        return emptyProductPage(page, limit)
      }
      console.log('[getSmartRecommendations] 开始获取智能推荐...')
      
      const products: Product[] = []
      const addedIds = new Set<string>()
      const requiredCount = page * limit + 1
      
      // 1. 根据用户搜索历史推荐商品（权重最高）
      const searchHistory = await this.getUserSearchHistory(5)
      console.log('[getSmartRecommendations] 用户搜索历史:', searchHistory)
      
      if (searchHistory.length > 0) {
        // 根据搜索关键词查找商品
        const keywordProducts = await this.searchProductsByKeywords(searchHistory, requiredCount)
        for (let i = 0; i < keywordProducts.length; i++) {
          const prod = keywordProducts[i]
          if (!addedIds.has(prod.id)) {
            products.push(prod)
            addedIds.add(prod.id)
          }
        }
      }
      
      // 2. 根据用户浏览历史推荐相似分类商品
      if (products.length < requiredCount) {
        const browseCategories = await this.getUserBrowseCategories(3)
        console.log('[getSmartRecommendations] 用户浏览分类:', browseCategories)
        
        if (browseCategories.length > 0) {
          const categoryProducts = await this.getProductsByCategories(browseCategories, requiredCount - products.length)
          for (let i = 0; i < categoryProducts.length; i++) {
            const prod = categoryProducts[i]
            if (!addedIds.has(prod.id)) {
              products.push(prod)
              addedIds.add(prod.id)
              if (products.length >= requiredCount) break
            }
          }
        }
      }
      
      // 3. 补充热销商品
      if (products.length < requiredCount) {
        const hotProducts = await this.getHotProducts(requiredCount - products.length + 5)
        for (let i = 0; i < hotProducts.length; i++) {
          const prod = hotProducts[i]
          if (!addedIds.has(prod.id)) {
            products.push(prod)
            addedIds.add(prod.id)
            if (products.length >= requiredCount) break
          }
        }
      }
      
      // 4. 如果还不够，用普通商品补充
      if (products.length < requiredCount) {
        const moreProducts = await this.getProductsByPrice(1, requiredCount - products.length + 5, false)
        for (let i = 0; i < moreProducts.data.length; i++) {
          const prod = moreProducts.data[i]
          if (!addedIds.has(prod.id)) {
            products.push(prod)
            addedIds.add(prod.id)
            if (products.length >= requiredCount) break
          }
        }
      }
      
      const startIndex = (page - 1) * limit
      const endIndex = startIndex + limit
      const pageData = products.slice(startIndex, endIndex)
      console.log('[getSmartRecommendations] 返回商品数量:', pageData.length)
      logConsumerQuerySuccess('getSmartRecommendations', 'ml_products_detail_view', pageData.length)
      return {
        data: pageData,
        total: products.length,
        page,
        limit,
        hasmore: products.length > endIndex
      }
    } catch (e) {
      logConsumerQueryFailure('getSmartRecommendations', 'ml_products_detail_view', e)
      console.error('获取智能推荐失败:', e)
      return emptyProductPage(page, limit)
    }
  }

  // 根据关键词列表搜索商品
  async searchProductsByKeywords(keywords: string[], limit: number): Promise<Product[]> {
    try {
      const response = await supa
        .from('ml_products_detail_view')
        .select('id, name, description, base_price, market_price, main_image_url, image_urls, category_id, brand_id, merchant_id, total_stock, sale_count, status, is_featured, is_new, is_hot')
        .order('sale_count', { ascending: false })
        .limit(limit * 2)
        .execute()
      
      if (response.error != null || response.data == null) {
        return [] as Product[]
      }
      
      const products: Product[] = []
      const rawList = response.data as any[]
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const prodObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        // 手动过滤 status
        const rawStatus = prodObj.get('status')
        let statusNum: number = 0
        if (typeof rawStatus == 'number') {
          statusNum = rawStatus as number
        }
        if (statusNum !== 1) continue
        
        // 检查是否匹配任何关键词
        const name = safeGetString(prodObj, 'name').toLowerCase()
        const desc = safeGetString(prodObj, 'description').toLowerCase()
        
        let matched = false
        for (let j = 0; j < keywords.length; j++) {
          const keyword = keywords[j].toLowerCase()
          if (name.indexOf(keyword) >= 0 || desc.indexOf(keyword) >= 0) {
            matched = true
            break
          }
        }
        
        if (!matched) continue
        
        products.push(parseProductFromRaw(item))
        if (products.length >= limit) break
      }
      
      return products
    } catch (e) {
      console.error('根据关键词搜索商品失败:', e)
      return [] as Product[]
    }
  }

  // 根据分类列表获取商品
  async getProductsByCategories(categoryIds: string[], limit: number): Promise<Product[]> {
    try {
      const response = await supa
        .from('ml_products_detail_view')
        .select('id, name, description, base_price, market_price, main_image_url, image_urls, category_id, brand_id, merchant_id, total_stock, sale_count, status, is_featured, is_new, is_hot')
        .order('sale_count', { ascending: false })
        .limit(limit * 2)
        .execute()
      
      if (response.error != null || response.data == null) {
        return [] as Product[]
      }
      
      const products: Product[] = []
      const rawList = response.data as any[]
      
      for (let i = 0; i < rawList.length; i++) {
        const item = rawList[i]
        const prodObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
        
        // 手动过滤 status
        const rawStatus = prodObj.get('status')
        let statusNum: number = 0
        if (typeof rawStatus == 'number') {
          statusNum = rawStatus as number
        }
        if (statusNum !== 1) continue
        
        // 手动过滤 category_id
        const rawCatId = prodObj.get('category_id')
        const itemCatId = (typeof rawCatId == 'string') ? (rawCatId as string) : ''
        
        let matched = false
        for (let j = 0; j < categoryIds.length; j++) {
          if (itemCatId == categoryIds[j]) {
            matched = true
            break
          }
        }
        
        if (!matched) continue
        
        products.push(parseProductFromRaw(item))
        if (products.length >= limit) break
      }
      
      return products
    } catch (e) {
      console.error('根据分类获取商品失败:', e)
      return [] as Product[]
    }
  }

  // 记录用户搜索行为
  async recordSearch(keyword: string, resultCount: number): Promise<void> {
    try {
      const userId = this.getCurrentUserId()
      const searchRecord = new UTSJSONObject()
      searchRecord.set('keyword', keyword)
      searchRecord.set('result_count', resultCount)
      if (userId != null) {
        searchRecord.set('user_id', userId)
      }
      
      await supa
        .from('ml_search_history')
        .insert(searchRecord)
        .execute()
    } catch (e) {
      console.error('记录搜索失败:', e)
    }
  }

  // 记录用户浏览行为
  async recordBrowse(productId: string, duration: number = 0): Promise<void> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return
      
      const browseRecord = new UTSJSONObject()
      browseRecord.set('user_id', userId)
      browseRecord.set('product_id', productId)
      browseRecord.set('browse_duration', duration)
      browseRecord.set('created_at', new Date().toISOString())
      
      // UTS Android不支持upsert，使用insert
      await supa
        .from('ml_browse_history')
        .insert(browseRecord)
        .execute()
    } catch (e) {
      console.error('记录浏览失败:', e)
    }
  }

  // ==================== 签到相关API ====================

  // 用户签到
  async signin(): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('success', false)
    result.set('points', 0)
    result.set('continuous_days', 0)
    result.set('bonus_points', 0)
    result.set('total_points', 0)
    result.set('message', '')

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        result.set('message', '请先登录')
        return result
      }

      const today = new Date()
      const todayStr = today.toISOString().split('T')[0]
      const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000)
      const yesterdayStr = yesterday.toISOString().split('T')[0]

      // 检查今天是否已签到
      const checkRes = await supa
        .from('ml_signin_records')
        .select('*')
        .eq('user_id', userId!)
        .eq('signin_date', todayStr)
        .execute()

      if (checkRes.error != null) {
        result.set('message', '查询签到状态失败')
        return result
      }

      const checkData = checkRes.data as any[]
      if (checkData != null && checkData.length > 0) {
        result.set('message', '今天已签到')
        return result
      }

      // 查询昨天是否签到，计算连续天数
      const yesterdayRes = await supa
        .from('ml_signin_records')
        .select('continuous_days')
        .eq('user_id', userId!)
        .eq('signin_date', yesterdayStr)
        .execute()

      let continuousDays = 1
      if (yesterdayRes.error == null && yesterdayRes.data != null) {
        const yData = yesterdayRes.data as any[]
        if (yData.length > 0) {
          const yItem = yData[0]
          let yDays = 0
          if (yItem instanceof UTSJSONObject) {
            yDays = yItem.getNumber('continuous_days') ?? 0
          } else {
            const yObj = JSON.parse(JSON.stringify(yItem)) as UTSJSONObject
            yDays = yObj.getNumber('continuous_days') ?? 0
          }
          continuousDays = yDays + 1
        }
      }

      // 计算积分
      let pointsEarned = 5 // 每日签到基础积分
      let bonusPoints = 0

      if (continuousDays >= 30) {
        bonusPoints = 100
      } else if (continuousDays >= 7) {
        bonusPoints = 20
      }

      const totalPointsEarned = pointsEarned + bonusPoints

      // 插入签到记录
      const signinRecord = new UTSJSONObject()
      signinRecord.set('user_id', userId!)
      signinRecord.set('signin_date', todayStr)
      signinRecord.set('points_earned', pointsEarned)
      signinRecord.set('bonus_points', bonusPoints)
      signinRecord.set('continuous_days', continuousDays)

      const insertRes = await supa
        .from('ml_signin_records')
        .insert(signinRecord)
        .execute()

      if (insertRes.error != null) {
        result.set('message', '签到失败')
        return result
      }

      // 更新用户积分
      await this.addPoints(userId!, totalPointsEarned, 'signin', '每日签到')

      // 获取最新积分
      const newPoints = await this.getUserPoints()

      result.set('success', true)
      result.set('points', pointsEarned)
      result.set('continuous_days', continuousDays)
      result.set('bonus_points', bonusPoints)
      result.set('total_points', newPoints)
      result.set('message', '签到成功')

      return result
    } catch (e) {
      console.error('签到异常:', e)
      result.set('message', '签到异常')
      return result
    }
  }

  // 获取签到记录（当月）
  async getSigninRecords(year: number, month: number): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const startDate = `${year}-${month.toString().padStart(2, '0')}-01`
      const endDate = month === 12 
        ? `${year + 1}-01-01` 
        : `${year}-${(month + 1).toString().padStart(2, '0')}-01`

      const response = await supa
        .from('ml_signin_records')
        .select('*')
        .eq('user_id', userId!)
        .gte('signin_date', startDate)
        .lt('signin_date', endDate)
        .order('signin_date', { ascending: true })
        .execute()

      if (response.error != null || response.data == null) {
        const empty: any[] = []
        return empty
      }

      return response.data as any[]
    } catch (e) {
      console.error('获取签到记录失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 获取今日签到状态
  async getTodaySigninStatus(): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('signed', false)
    result.set('continuous_days', 0)

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return result

      const today = new Date().toISOString().split('T')[0]

      // 检查今天是否签到
      const todayRes = await supa
        .from('ml_signin_records')
        .select('*')
        .eq('user_id', userId!)
        .eq('signin_date', today)
        .execute()

      if (todayRes.error == null && todayRes.data != null) {
        const tData = todayRes.data as any[]
        if (tData.length > 0) {
          const tItem = tData[0]
          let cDays = 0
          if (tItem instanceof UTSJSONObject) {
            cDays = tItem.getNumber('continuous_days') ?? 0
          } else {
            const tObj = JSON.parse(JSON.stringify(tItem)) as UTSJSONObject
            cDays = tObj.getNumber('continuous_days') ?? 0
          }
          result.set('signed', true)
          result.set('continuous_days', cDays)
          return result
        }
      }

      // 今天未签到，获取最近的连续签到天数
      const lastRes = await supa
        .from('ml_signin_records')
        .select('continuous_days, signin_date')
        .eq('user_id', userId!)
        .order('signin_date', { ascending: false })
        .limit(1)
        .execute()

      if (lastRes.error == null && lastRes.data != null) {
        const lData = lastRes.data as any[]
        if (lData.length > 0) {
          const lItem = lData[0]
          let lastDate = ''
          let lastDays = 0
          if (lItem instanceof UTSJSONObject) {
            lastDate = lItem.getString('signin_date') ?? ''
            lastDays = lItem.getNumber('continuous_days') ?? 0
          } else {
            const lObj = JSON.parse(JSON.stringify(lItem)) as UTSJSONObject
            lastDate = lObj.getString('signin_date') ?? ''
            lastDays = lObj.getNumber('continuous_days') ?? 0
          }

          const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().split('T')[0]
          if (lastDate === yesterday) {
            result.set('continuous_days', lastDays)
          }
        }
      }

      return result
    } catch (e) {
      console.error('获取签到状态失败:', e)
      return result
    }
  }

  // ==================== 积分兑换相关API ====================

  // 获取积分兑换商品列表
  async getPointProducts(): Promise<any[]> {
    try {
      const response = await supa
        .from('ml_point_products')
        .select('*')
        .eq('status', 1)
        .gt('stock', 0)
        .order('sort_order', { ascending: true })
        .execute()

      if (response.error != null || response.data == null) {
        const empty: any[] = []
        return empty
      }

      return response.data as any[]
    } catch (e) {
      console.error('获取积分商品失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 积分兑换
  async exchangeProduct(productId: string, quantity: number, addressSnapshot: UTSJSONObject | null): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('success', false)
    result.set('message', '')

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        result.set('message', '请先登录')
        return result
      }

      // 获取商品信息
      const productRes = await supa
        .from('ml_point_products')
        .select('*')
        .eq('id', productId)
        .single()
        .execute()

      if (productRes.error != null || productRes.data == null) {
        result.set('message', '商品不存在')
        return result
      }

      const productRaw = productRes.data
      let pointsRequired = 0
      let stock = 0
      let productType = ''
      
      // 检查是否是数组，如果是则取第一个元素
      let productObj: UTSJSONObject | null = null
      if (Array.isArray(productRaw)) {
        const arr = productRaw as any[]
        if (arr.length > 0) {
          const firstItem = arr[0]
          if (firstItem instanceof UTSJSONObject) {
            productObj = firstItem
          } else {
            productObj = JSON.parse(JSON.stringify(firstItem)) as UTSJSONObject
          }
        }
      } else {
        if (productRaw instanceof UTSJSONObject) {
          productObj = productRaw
        } else {
          productObj = JSON.parse(JSON.stringify(productRaw)) as UTSJSONObject
        }
      }
      
      // 使用 UTSJSONObject 方法访问属性
      if (productObj != null) {
        pointsRequired = productObj.getNumber('points_required') ?? 0
        stock = productObj.getNumber('stock') ?? 0
        productType = productObj.getString('product_type') ?? ''
      }

      const totalPoints = pointsRequired * quantity

      // 检查库存
      if (stock < quantity) {
        result.set('message', '库存不足')
        return result
      }

      // 检查积分
      const userPoints = await this.getUserPoints()
      if (userPoints < totalPoints) {
        result.set('message', '积分不足')
        return result
      }

      // 创建兑换记录
      const exchangeRecord = new UTSJSONObject()
      exchangeRecord.set('user_id', userId!)
      exchangeRecord.set('product_id', productId)
      exchangeRecord.set('quantity', quantity)
      exchangeRecord.set('points_used', totalPoints)
      exchangeRecord.set('status', 0)
      if (addressSnapshot != null && productType === 'physical') {
        exchangeRecord.set('address_snapshot', JSON.stringify(addressSnapshot))
      }

      const insertRes = await supa
        .from('ml_point_exchanges')
        .insert(exchangeRecord)
        .execute()

      if (insertRes.error != null) {
        console.error('[exchangeProduct] 创建兑换记录失败:', insertRes.error)
        result.set('message', '兑换失败')
        return result
      }
      
      console.log('[exchangeProduct] 兑换记录创建成功')

      // 扣减库存
      console.log('[exchangeProduct] 准备扣减库存')
      console.log('[exchangeProduct] productId 类型:', typeof productId)
      console.log('[exchangeProduct] productId 值:', productId)
      console.log('[exchangeProduct] 当前库存:', stock, ', 扣减数量:', quantity)
      
      // 使用 UTSJSONObject 替代 Record<string, any>
      const stockUpdateData = new UTSJSONObject()
      stockUpdateData.set('stock', stock - quantity)
      
      console.log('[exchangeProduct] stockUpdateData:', stockUpdateData)
      console.log('[exchangeProduct] stockUpdateData 类型:', typeof stockUpdateData)
      
      // 先查询确认商品存在
      const checkProduct = await supa
        .from('ml_point_products')
        .select('id, stock')
        .eq('id', productId)
        .execute()
      console.log('[exchangeProduct] 查询商品结果:', checkProduct.data, 'error:', checkProduct.error)
      
      const stockUpdateRes = await supa
        .from('ml_point_products')
        .update(stockUpdateData)
        .eq('id', productId)
        .execute()
      
      console.log('[exchangeProduct] 库存更新结果 error:', stockUpdateRes.error)
      console.log('[exchangeProduct] 库存更新结果 data:', stockUpdateRes.data)
      
      if (stockUpdateRes.error != null) {
        console.error('[exchangeProduct] 扣减库存失败:', stockUpdateRes.error)
      }

      // 扣减积分
      console.log('[exchangeProduct] 准备扣减积分, userId:', userId, ', 积分:', totalPoints)
      const deductResult = await this.deductPoints(userId!, totalPoints, 'redeem', '积分兑换商品')
      console.log('[exchangeProduct] 积分扣减结果:', deductResult)
      
      if (!deductResult) {
        console.error('[exchangeProduct] 扣减积分失败')
      }

      console.log('[exchangeProduct] 兑换流程完成')
      result.set('success', true)
      result.set('message', '兑换成功')
      return result
    } catch (e) {
      console.error('积分兑换异常:', e)
      result.set('message', '兑换异常')
      return result
    }
  }

  // 获取兑换记录
  async getExchangeRecords(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const response = await supa
        .from('ml_point_exchanges')
        .select('*, product:ml_point_products(name, image_url, product_type)')
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .execute()

      if (response.error != null || response.data == null) {
        const empty: any[] = []
        return empty
      }

      return response.data as any[]
    } catch (e) {
      console.error('获取兑换记录失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // ==================== 评价相关API ====================

  // 获取商品评价列表
  async getProductReviews(productId: string, page: number = 1, limit: number = 10, rating: number = 0, hasImage: boolean = false): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('total', 0)
    result.set('page', page)
    result.set('limit', limit)
    result.set('data', [] as any[])

    try {
      const userId = this.getCurrentUserId()
      
      let query = supa
        .from('ml_product_reviews')
        .select('*, user:auth.users!ml_product_reviews_user_id_fkey(raw_user_meta_data)', { count: 'exact' })
        .eq('product_id', productId)

      if (rating > 0) {
        query = query.eq('rating', rating)
      }

      if (hasImage) {
        query = query.neq('images', '[]')
      }

      const offset = (page - 1) * limit
      const response = await query
        .order('created_at', { ascending: false })
        .range(offset, offset + limit - 1)
        .execute()

      if (response.error != null) {
        console.error('获取评价列表失败:', response.error)
        return result
      }

      const total = response.total ?? 0
      const reviews = response.data as any[]

      // 处理评价数据
      const processedReviews: any[] = []
      for (let i = 0; i < reviews.length; i++) {
        const review = reviews[i]
        const processed = JSON.parse(JSON.stringify(review)) as UTSJSONObject

        // 处理用户信息
        const userRaw = processed.get('user')
        let userName = '匿名用户'
        let userAvatar = ''

        if (userRaw != null) {
          let userData: UTSJSONObject
          if (userRaw instanceof UTSJSONObject) {
            userData = userRaw as UTSJSONObject
          } else {
            userData = JSON.parse(JSON.stringify(userRaw)) as UTSJSONObject
          }
          const metaData = userData.get('raw_user_meta_data')
          if (metaData != null) {
            let metaObj: UTSJSONObject
            if (metaData instanceof UTSJSONObject) {
              metaObj = metaData as UTSJSONObject
            } else {
              metaObj = JSON.parse(JSON.stringify(metaData)) as UTSJSONObject
            }
            userName = metaObj.getString('nickname') ?? metaObj.getString('name') ?? '匿名用户'
            userAvatar = metaObj.getString('avatar_url') ?? ''
          }
        }

        // 检查是否匿名
        const isAnonymous = processed.getBoolean('is_anonymous') ?? false
        if (isAnonymous) {
          userName = '匿名用户'
          userAvatar = ''
        }

        processed.set('user_name', userName)
        processed.set('user_avatar', userAvatar)

        // 检查当前用户是否点赞
        let isLiked = false
        if (userId != null) {
          const likeRes = await supa
            .from('ml_review_likes')
            .select('id')
            .eq('review_id', processed.getString('id') ?? '')
            .eq('user_id', userId!)
            .limit(1)
            .execute()
          if (likeRes.error == null && likeRes.data != null) {
            const likeData = likeRes.data as any[]
            isLiked = likeData.length > 0
          }
        }
        processed.set('is_liked', isLiked)

        processedReviews.push(processed)
      }

      result.set('total', total)
      result.set('data', processedReviews)
      return result
    } catch (e) {
      console.error('获取评价列表异常:', e)
      return result
    }
  }

  // 获取商品评价统计
  async getReviewStats(productId: string): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('total_count', 0)
    result.set('avg_rating', 0)
    result.set('good_rate', 0)
    result.set('rating_distribution', new UTSJSONObject())
    result.set('tags', [] as any[])

    try {
      const response = await supa
        .from('ml_product_reviews')
        .select('rating')
        .eq('product_id', productId)
        .execute()

      if (response.error != null || response.data == null) {
        return result
      }

      const reviews = response.data as any[]
      const totalCount = reviews.length

      if (totalCount === 0) return result

      let totalRating = 0
      let goodCount = 0
      const distribution: Map<number, number> = new Map()
      distribution.set(1, 0)
      distribution.set(2, 0)
      distribution.set(3, 0)
      distribution.set(4, 0)
      distribution.set(5, 0)

      for (let i = 0; i < reviews.length; i++) {
        const review = reviews[i]
        let rating = 0
        if (review instanceof UTSJSONObject) {
          rating = review.getNumber('rating') ?? 0
        } else {
          const rObj = JSON.parse(JSON.stringify(review)) as UTSJSONObject
          rating = rObj.getNumber('rating') ?? 0
        }

        totalRating += rating
        if (rating >= 4) goodCount++

        const currentCount = distribution.get(rating) ?? 0
        distribution.set(rating, currentCount + 1)
      }

      const avgRating = Math.round((totalRating / totalCount) * 10) / 10
      const goodRate = Math.round((goodCount / totalCount) * 100)

      const distObj = new UTSJSONObject()
      distribution.forEach((value: number, key: number) => {
        distObj.set(key.toString(), value)
      })

      result.set('total_count', totalCount)
      result.set('avg_rating', avgRating)
      result.set('good_rate', goodRate)
      result.set('rating_distribution', distObj)

      return result
    } catch (e) {
      console.error('获取评价统计异常:', e)
      return result
    }
  }

  // 评价点赞
  async toggleReviewLike(reviewId: string): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('success', false)
    result.set('is_liked', false)
    result.set('like_count', 0)

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        return result
      }

      // 检查是否已点赞
      const checkRes = await supa
        .from('ml_review_likes')
        .select('id')
        .eq('review_id', reviewId)
        .eq('user_id', userId!)
        .limit(1)
        .execute()

      let isLiked = false
      if (checkRes.error == null && checkRes.data != null) {
        const checkData = checkRes.data as any[]
        isLiked = checkData.length > 0
      }

      if (isLiked) {
        // 取消点赞
        await supa
          .from('ml_review_likes')
          .eq('review_id', reviewId)
          .eq('user_id', userId!)
          .delete()
          .execute()

        // 更新点赞数 - 直接查询并更新
        const currentCountRes = await supa
          .from('ml_product_reviews')
          .select('like_count')
          .eq('id', reviewId)
          .single()
          .execute()
        
        if (currentCountRes.error == null && currentCountRes.data != null) {
          let currentCount = 0
          if (currentCountRes.data instanceof UTSJSONObject) {
            currentCount = currentCountRes.data.getNumber('like_count') ?? 0
          } else {
            const countObj = JSON.parse(JSON.stringify(currentCountRes.data)) as UTSJSONObject
            currentCount = countObj.getNumber('like_count') ?? 0
          }
          
          const updateData = new UTSJSONObject()
          updateData.set('like_count', Math.max(0, currentCount - 1))
          await supa
            .from('ml_product_reviews')
            .update(updateData)
            .eq('id', reviewId)
            .execute()
        }

        result.set('is_liked', false)
      } else {
        // 添加点赞
        const likeRecord = new UTSJSONObject()
        likeRecord.set('review_id', reviewId)
        likeRecord.set('user_id', userId!)

        await supa
          .from('ml_review_likes')
          .insert(likeRecord)
          .execute()

        // 更新点赞数 - 直接查询并更新
        const currentCountRes = await supa
          .from('ml_product_reviews')
          .select('like_count')
          .eq('id', reviewId)
          .single()
          .execute()
        
        if (currentCountRes.error == null && currentCountRes.data != null) {
          let currentCount = 0
          if (currentCountRes.data instanceof UTSJSONObject) {
            currentCount = currentCountRes.data.getNumber('like_count') ?? 0
          } else {
            const countObj = JSON.parse(JSON.stringify(currentCountRes.data)) as UTSJSONObject
            currentCount = countObj.getNumber('like_count') ?? 0
          }
          
          const updateData = new UTSJSONObject()
          updateData.set('like_count', currentCount + 1)
          await supa
            .from('ml_product_reviews')
            .update(updateData)
            .eq('id', reviewId)
            .execute()
        }

        result.set('is_liked', true)
      }

      // 获取最新点赞数
      const reviewRes = await supa
        .from('ml_product_reviews')
        .select('like_count')
        .eq('id', reviewId)
        .single()
        .execute()

      if (reviewRes.error == null && reviewRes.data != null) {
        let likeCount = 0
        if (reviewRes.data instanceof UTSJSONObject) {
          likeCount = reviewRes.data.getNumber('like_count') ?? 0
        } else {
          const rObj = JSON.parse(JSON.stringify(reviewRes.data)) as UTSJSONObject
          likeCount = rObj.getNumber('like_count') ?? 0
        }
        result.set('like_count', likeCount)
      }

      result.set('success', true)
      return result
    } catch (e) {
      console.error('评价点赞异常:', e)
      return result
    }
  }

  // 获取我的评价列表
  async getMyReviews(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const response = await supa
        .from('ml_product_reviews')
        .select(`
          *,
          product:ml_products!ml_product_reviews_product_id_fkey(name, main_image_url)
        `)
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .execute()

      if (response.error != null || response.data == null) {
        const empty: any[] = []
        return empty
      }

      const reviews = response.data as any[]
      const result: any[] = []

      for (let i = 0; i < reviews.length; i++) {
        const review = reviews[i]
        const processed = JSON.parse(JSON.stringify(review)) as UTSJSONObject

        // 处理商品信息
        const productRaw = processed.get('product')
        let productName = ''
        let productImage = ''
        if (productRaw != null) {
          let productObj: UTSJSONObject
          if (productRaw instanceof UTSJSONObject) {
            productObj = productRaw as UTSJSONObject
          } else {
            productObj = JSON.parse(JSON.stringify(productRaw)) as UTSJSONObject
          }
          productName = productObj.getString('name') ?? ''
          productImage = productObj.getString('main_image_url') ?? ''
        }
        processed.set('product_name', productName)
        processed.set('product_image', productImage)

        // 计算是否可追加评价（7天内）
        const createdAt = processed.getString('created_at') ?? ''
        const createdTime = new Date(createdAt).getTime()
        const now = Date.now()
        const sevenDays = 7 * 24 * 60 * 60 * 1000
        const canAppend = (now - createdTime) < sevenDays && (processed.getString('append_content') ?? '') === ''
        processed.set('can_append', canAppend)

        // 计算是否可编辑（24小时内）
        const oneDay = 24 * 60 * 60 * 1000
        const canEdit = (now - createdTime) < oneDay
        processed.set('can_edit', canEdit)

        result.push(processed)
      }

      return result
    } catch (e) {
      console.error('获取我的评价失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 追加评价
  async appendReview(reviewId: string, content: string, images: string[]): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return false

      const updateData = new UTSJSONObject()
      updateData.set('append_content', content)
      updateData.set('append_images', JSON.stringify(images))
      updateData.set('append_at', new Date().toISOString())

      const response = await supa
        .from('ml_product_reviews')
        .update(updateData)
        .eq('id', reviewId)
        .eq('user_id', userId!)
        .execute()

      return response.error == null
    } catch (e) {
      console.error('追加评价失败:', e)
      return false
    }
  }

  // 删除评价
  async deleteReview(reviewId: string): Promise<boolean> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return false

      const response = await supa
        .from('ml_product_reviews')
        .delete()
        .eq('id', reviewId)
        .eq('user_id', userId!)
        .execute()

      return response.error == null
    } catch (e) {
      console.error('删除评价失败:', e)
      return false
    }
  }

  // ==================== 积分辅助方法 ====================

  // 增加积分
  private async addPoints(userId: string, points: number, type: string, description: string): Promise<boolean> {
    try {
      // 获取当前积分
      const currentPoints = await this.getUserPoints()
      const newPoints = currentPoints + points
      const totalEarned = await this.getTotalEarned()

      // 检查用户积分记录是否存在
      const checkRes = await supa
        .from('ml_user_points')
        .select('user_id')
        .eq('user_id', userId)
        .limit(1)
        .execute()

      const exists = checkRes.error == null && checkRes.data != null && (checkRes.data as any[]).length > 0

      if (exists) {
        // 更新现有记录
        const updateData = new UTSJSONObject()
        updateData.set('points', newPoints)
        updateData.set('total_earned', totalEarned + points)
        updateData.set('updated_at', new Date().toISOString())

        await supa
          .from('ml_user_points')
          .update(updateData)
          .eq('user_id', userId)
          .execute()
      } else {
        // 插入新记录
        const insertData = new UTSJSONObject()
        insertData.set('user_id', userId)
        insertData.set('points', newPoints)
        insertData.set('total_earned', points)
        insertData.set('updated_at', new Date().toISOString())

        await supa
          .from('ml_user_points')
          .insert(insertData)
          .execute()
      }

      // 记录积分变动
      const record = new UTSJSONObject()
      record.set('user_id', userId)
      record.set('points', points)
      record.set('type', type)
      record.set('description', description)

      await supa
        .from('ml_point_records')
        .insert(record)
        .execute()

      return true
    } catch (e) {
      console.error('增加积分失败:', e)
      return false
    }
  }

  // 扣减积分
  private async deductPoints(userId: string, points: number, type: string, description: string): Promise<boolean> {
    try {
      const currentPoints = await this.getUserPoints()
      const newPoints = currentPoints - points

      if (newPoints < 0) return false

      const updateData = new UTSJSONObject()
      updateData.set('points', newPoints)
      updateData.set('updated_at', new Date().toISOString())

      await supa
        .from('ml_user_points')
        .update(updateData)
        .eq('user_id', userId)
        .execute()

      const record = new UTSJSONObject()
      record.set('user_id', userId)
      record.set('points', -points)
      record.set('type', type)
      record.set('description', description)

      await supa
        .from('ml_point_records')
        .insert(record)
        .execute()

      return true
    } catch (e) {
      console.error('扣减积分失败:', e)
      return false
    }
  }

  // 获取历史累计积分
  private async getTotalEarned(): Promise<number> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return 0

      const res = await supa
        .from('ml_user_points')
        .select('total_earned')
        .eq('user_id', userId!)
        .single()
        .execute()

      if (res.error == null && res.data != null) {
        if (res.data instanceof UTSJSONObject) {
          return res.data.getNumber('total_earned') ?? 0
        } else {
          const obj = JSON.parse(JSON.stringify(res.data)) as UTSJSONObject
          return obj.getNumber('total_earned') ?? 0
        }
      }
      return 0
    } catch (e) {
      return 0
    }
  }

  // ==================== 积分过期相关API ====================

  // 获取即将过期积分
  async getExpiringPoints(): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('expiring_points', 0)
    result.set('expiring_date', null)
    result.set('details', [] as any[])

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return result

      // 查询30天内即将过期的积分记录
      const now = new Date()
      const thirtyDaysLater = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000)
      const nowStr = now.toISOString()
      const laterStr = thirtyDaysLater.toISOString()

      const res = await supa
        .from('ml_point_records')
        .select('points, description, expires_at, created_at')
        .eq('user_id', userId!)
        .gt('points', 0)
        .eq('is_expired', false)
        .not('expires_at', 'is', null)
        .gte('expires_at', nowStr)
        .lte('expires_at', laterStr)
        .order('expires_at', { ascending: true })
        .execute()

      if (res.error != null) {
        console.error('获取即将过期积分失败:', res.error)
        return result
      }

      if (res.data != null && Array.isArray(res.data)) {
        const records = res.data as any[]
        let totalExpiring = 0
        let earliestDate: string | null = null
        const details: any[] = []

        for (let i = 0; i < records.length; i++) {
          const record = records[i]
          let recordObj: UTSJSONObject
          if (record instanceof UTSJSONObject) {
            recordObj = record
          } else {
            recordObj = JSON.parse(JSON.stringify(record)) as UTSJSONObject
          }

          const points = recordObj.getNumber('points') ?? 0
          const expiresAt = recordObj.getString('expires_at') ?? ''

          totalExpiring += points

          if (earliestDate == null || expiresAt < earliestDate) {
            earliestDate = expiresAt
          }

          details.push({
            points: points,
            description: recordObj.getString('description'),
            expires_at: expiresAt,
            created_at: recordObj.getString('created_at') ?? ''
          })
        }

        result.set('expiring_points', totalExpiring)
        result.set('expiring_date', earliestDate != null ? earliestDate.split('T')[0] : null)
        result.set('details', details)
      }

      return result
    } catch (e) {
      console.error('获取即将过期积分异常:', e)
      return result
    }
  }

  // 获取积分概览（包含即将过期积分）
  async getPointsOverview(): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('current_points', 0)
    result.set('total_earned', 0)
    result.set('expiring_points', 0)
    result.set('expiring_date', null)

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return result

      const res = await supa
        .from('ml_user_points')
        .select('points, total_earned, expiring_points, expiring_date')
        .eq('user_id', userId!)
        .single()
        .execute()

      if (res.error == null && res.data != null) {
        let data: UTSJSONObject
        if (res.data instanceof UTSJSONObject) {
          data = res.data as UTSJSONObject
        } else {
          data = JSON.parse(JSON.stringify(res.data)) as UTSJSONObject
        }

        result.set('current_points', data.getNumber('points') ?? 0)
        result.set('total_earned', data.getNumber('total_earned') ?? 0)
        result.set('expiring_points', data.getNumber('expiring_points') ?? 0)
        result.set('expiring_date', data.getString('expiring_date'))
      }

      return result
    } catch (e) {
      console.error('获取积分概览异常:', e)
      return result
    }
  }

  // 获取过期提醒通知列表
  async getExpiryNotifications(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const res = await supa
        .from('ml_point_expiry_notifications')
        .select('*')
        .eq('user_id', userId!)
        .eq('is_sent', false)
        .order('expiry_date', { ascending: true })
        .execute()

      if (res.error != null || res.data == null) {
        const empty: any[] = []
        return empty
      }

      return res.data as any[]
    } catch (e) {
      console.error('获取过期提醒失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 标记过期提醒为已读
  async markNotificationRead(notificationId: string): Promise<boolean> {
    try {
      const res = await supa
        .from('ml_point_expiry_notifications')
        .update({ is_sent: true, sent_at: new Date().toISOString() })
        .eq('id', notificationId)
        .execute()

      return res.error == null
    } catch (e) {
      console.error('标记通知失败:', e)
      return false
    }
  }

  // 手动触发积分维护任务（管理员功能）
  // 注意：UTS不支持rpc，此功能需要在Supabase后台手动执行或通过其他方式触发
  async triggerPointsMaintenance(): Promise<boolean> {
    console.warn('triggerPointsMaintenance: UTS不支持rpc调用，请在Supabase后台手动执行 daily_points_maintenance()')
    return false
  }

  // ==================== 推销模式 - 商家配置API ====================

  // 获取商家推销配置
  async getMerchantPromotionConfig(merchantId: string): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('promotion_enabled', false)
    result.set('share_free_enabled', false)
    result.set('distribution_enabled', false)
    result.set('required_count', 4)
    result.set('reward_type', 'product_price')
    result.set('fixed_reward_amount', 0)

    try {
      const res = await supa
        .from('ml_merchant_promotion_config')
        .select('*')
        .eq('merchant_id', merchantId)
        .limit(1)
        .execute()

      if (res.error == null && res.data != null && Array.isArray(res.data)) {
        const arr = res.data as any[]
        if (arr.length > 0) {
          const item = arr[0]
          const itemAny = item as any
          
          if (itemAny instanceof UTSJSONObject) {
            result.set('promotion_enabled', itemAny.getBoolean('promotion_enabled') ?? false)
            result.set('share_free_enabled', itemAny.getBoolean('share_free_enabled') ?? false)
            result.set('distribution_enabled', itemAny.getBoolean('distribution_enabled') ?? false)
            result.set('required_count', itemAny.getNumber('required_count') ?? 4)
            result.set('reward_type', itemAny.getString('reward_type') ?? 'product_price')
            result.set('fixed_reward_amount', itemAny.getNumber('fixed_reward_amount') ?? 0)
          }
        }
      }
    } catch (e) {
      console.error('获取商家推销配置失败:', e)
    }

    return result
  }

  // 检查商家是否开启分享免单
  async isShareFreeEnabled(merchantId: string): Promise<boolean> {
    try {
      const config = await this.getMerchantPromotionConfig(merchantId)
      const promotionEnabled = config.get('promotion_enabled')
      const shareFreeEnabled = config.get('share_free_enabled')
      return (promotionEnabled === true || promotionEnabled === 'true') && 
             (shareFreeEnabled === true || shareFreeEnabled === 'true')
    } catch (e) {
      console.error('检查分享免单状态失败:', e)
      return false
    }
  }

  // ==================== 推销模式 - 余额相关API ====================

  // 获取用户余额
  async getUserBalance(): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('balance', 0)
    result.set('frozen_balance', 0)
    result.set('total_earned', 0)
    result.set('total_withdrawn', 0)

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return result

      const res = await supa
        .from('ml_user_balance')
        .select('*')
        .eq('user_id', userId!)
        .limit(1)
        .execute()

      if (res.error == null && res.data != null && Array.isArray(res.data)) {
        const arr = res.data as any[]
        if (arr.length > 0) {
          const item = arr[0]
          const itemAny = item as any
          if (itemAny instanceof UTSJSONObject) {
            result.set('balance', itemAny.getNumber('balance') ?? 0)
            result.set('frozen_balance', itemAny.getNumber('frozen_balance') ?? 0)
            result.set('total_earned', itemAny.getNumber('total_earned') ?? 0)
            result.set('total_withdrawn', itemAny.getNumber('total_withdrawn') ?? 0)
          }
        }
      }

      return result
    } catch (e) {
      console.error('获取用户余额失败:', e)
      return result
    }
  }

  // 获取余额变动记录
  async getBalanceRecords(page: number = 1, limit: number = 20): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const offset = (page - 1) * limit
      const res = await supa
        .from('ml_balance_records')
        .select('*')
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .range(offset, offset + limit - 1)
        .execute()

      if (res.error != null || res.data == null) {
        const empty: any[] = []
        return empty
      }

      return res.data as any[]
    } catch (e) {
      console.error('获取余额记录失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // ==================== 推销模式 - 分享免单相关API ====================

  // 创建分享记录
  async createShareRecord(productId: string, orderId: string, orderItemId: string | null, productName: string, productImage: string | null, productPrice: number): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('success', false)
    result.set('share_code', '')
    result.set('message', '')

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        result.set('message', '请先登录')
        return result
      }

      // 生成分享码
      const shareCode = this.generateShareCode()

      const insertData = new UTSJSONObject()
      insertData.set('user_id', userId)
      insertData.set('product_id', productId)
      insertData.set('order_id', orderId)
      insertData.set('order_item_id', orderItemId)
      insertData.set('share_code', shareCode)
      insertData.set('product_name', productName)
      insertData.set('product_image', productImage)
      insertData.set('product_price', productPrice)
      insertData.set('required_count', 4)
      insertData.set('current_count', 0)
      insertData.set('status', 0)

      const res = await supa
        .from('ml_share_records')
        .insert(insertData)
        .execute()

      if (res.error != null) {
        console.error('[createShareRecord] 插入失败:', res.error)
        console.error('[createShareRecord] 插入数据:', JSON.stringify(insertData))
        result.set('message', '创建分享记录失败: ' + (res.error.message ?? '未知错误'))
        return result
      }

      // 获取插入记录的id
      let insertedId = ''
      if (res.data != null && Array.isArray(res.data) && res.data.length > 0) {
        const inserted = res.data[0]
        let insertedObj: UTSJSONObject | null = null
        if (inserted instanceof UTSJSONObject) {
          insertedObj = inserted
        } else {
          insertedObj = JSON.parse(JSON.stringify(inserted)) as UTSJSONObject
        }
        insertedId = insertedObj.getString('id') ?? ''
      }

      result.set('success', true)
      result.set('id', insertedId)
      result.set('share_code', shareCode)
      result.set('message', '分享创建成功')
      return result
    } catch (e) {
      console.error('创建分享记录失败:', e)
      result.set('message', '创建分享记录异常')
      return result
    }
  }

  // 生成分享码
  private generateShareCode(): string {
    const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
    let result = ''
    for (let i = 0; i < 8; i++) {
      const randomIndex = Math.floor(Math.random() * chars.length)
      result += chars.charAt(randomIndex)
    }
    return result
  }

  // 验证分享码
  async validateShareCode(shareCode: string): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('valid', false)
    result.set('share_record', null)

    try {
      const res = await supa
        .from('ml_share_records')
        .select('*')
        .eq('share_code', shareCode)
        .eq('status', 0)
        .limit(1)
        .execute()

      if (res.error == null && res.data != null && Array.isArray(res.data)) {
        const arr = res.data as any[]
        if (arr.length > 0) {
          result.set('valid', true)
          result.set('share_record', arr[0])
        }
      }

      return result
    } catch (e) {
      console.error('验证分享码失败:', e)
      return result
    }
  }

  // 获取我的分享记录
  async getMyShareRecords(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const res = await supa
        .from('ml_share_records')
        .select('*')
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .execute()

      if (res.error != null || res.data == null) {
        const empty: any[] = []
        return empty
      }

      return res.data as any[]
    } catch (e) {
      console.error('获取分享记录失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 获取分享详情
  async getShareDetail(shareId: string): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('share_record', null)
    result.set('secondary_purchases', [] as any[])

    try {
      const res = await supa
        .from('ml_share_records')
        .select('*')
        .eq('id', shareId)
        .limit(1)
        .execute()

      if (res.error == null && res.data != null && Array.isArray(res.data)) {
        const arr = res.data as any[]
        if (arr.length > 0) {
          result.set('share_record', arr[0])
        }
      }

      // 获取二级购买记录
      const purchasesRes = await supa
        .from('ml_secondary_purchases')
        .select('*')
        .eq('share_record_id', shareId)
        .order('created_at', { ascending: false })
        .execute()

      if (purchasesRes.error == null && purchasesRes.data != null) {
        result.set('secondary_purchases', purchasesRes.data)
      }

      return result
    } catch (e) {
      console.error('获取分享详情失败:', e)
      return result
    }
  }

  // 获取免单奖励记录
  async getFreeOrderRewards(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const res = await supa
        .from('ml_free_order_rewards')
        .select('*')
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .execute()

      if (res.error != null || res.data == null) {
        const empty: any[] = []
        return empty
      }

      return res.data as any[]
    } catch (e) {
      console.error('获取免单奖励记录失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // ==================== 推销模式 - 会员等级相关API ====================

  // 获取会员等级列表
  async getMemberLevels(): Promise<any[]> {
    try {
      const res = await supa
        .from('ml_member_levels')
        .select('*')
        .eq('is_active', true)
        .order('level_rank', { ascending: true } as OrderOptions)
        .execute()

      if (res.error != null || res.data == null) {
        const empty: any[] = []
        return empty
      }

      return res.data as any[]
    } catch (e) {
      console.error('获取会员等级列表失败:', e)
      const empty: any[] = []
      return empty
    }
  }

  // 获取用户会员信息
  async getUserMemberInfo(): Promise<UTSJSONObject> {
    const result = new UTSJSONObject()
    result.set('member_level', 0)
    result.set('level_name', '普通会员')
    result.set('discount', 1.0)
    result.set('total_spent', 0)
    result.set('next_level', null)
    result.set('progress_percent', 0)
    result.set('manual_level', false)

    try {
      const userId = this.getCurrentUserId()
      if (userId == null) return result

      // 获取用户信息（包括 tier_id）
      const userRes = await supa
        .from('ml_user_profiles')
        .select('tier_id, total_spent, manual_level')
        .eq('user_id', userId!)
        .limit(1)
        .execute()

      let tierId: string = ''
      let totalSpent = 0
      let manualLevel = false

      if (userRes.error == null && userRes.data != null && Array.isArray(userRes.data)) {
        const arr = userRes.data as any[]
        if (arr.length > 0) {
          const item = arr[0]
          const itemAny = item as any
          if (itemAny instanceof UTSJSONObject) {
            tierId = itemAny.getString('tier_id') ?? ''
            totalSpent = itemAny.getNumber('total_spent') ?? 0
            manualLevel = itemAny.getBoolean('manual_level') ?? false
          }
        }
      }

      // 获取等级信息
      const levels = await this.getMemberLevels()
      let levelName = '普通会员'
      let discount = 1.0
      let nextLevel: UTSJSONObject | null = null
      let progressPercent = 0
      let currentLevelRank = 0

      // 通过 tier_id 匹配等级
      for (let i = 0; i < levels.length; i++) {
        const level = levels[i]
        const levelAny = level as any
        let levelId = ''
        let levelNameStr = ''
        let levelRank = 0
        let levelDiscount = 1.0

        if (levelAny instanceof UTSJSONObject) {
          levelId = levelAny.getString('id') ?? ''
          levelNameStr = levelAny.getString('name') ?? ''
          levelRank = levelAny.getNumber('level_rank') ?? 0
          levelDiscount = levelAny.getNumber('discount_rate') ?? 1.0
        }

        // 通过 tier_id 匹配当前等级
        if (levelId == tierId) {
          levelName = levelNameStr
          discount = levelDiscount
          currentLevelRank = levelRank
        }
      }

      // 找下一等级（level_rank 更大的第一个等级）
      for (let i = 0; i < levels.length; i++) {
        const level = levels[i]
        const levelAny = level as any
        let levelRank = 0
        let levelNameStr = ''
        let levelMinAmount = 0

        if (levelAny instanceof UTSJSONObject) {
          levelRank = levelAny.getNumber('level_rank') ?? 0
          levelNameStr = levelAny.getString('name') ?? ''
          levelMinAmount = levelAny.getNumber('min_amount') ?? 0
        }

        if (levelRank > currentLevelRank && nextLevel == null) {
          const nextLevelObj = new UTSJSONObject()
          const levelObj = level as UTSJSONObject
          nextLevelObj.set('id', levelObj.getString('id') ?? '')
          nextLevelObj.set('name', levelNameStr)
          nextLevelObj.set('min_amount', levelMinAmount)
          nextLevel = nextLevelObj
        }
      }

      result.set('member_level', currentLevelRank)
      result.set('level_name', levelName)
      result.set('discount', discount)
      result.set('total_spent', totalSpent)
      result.set('next_level', nextLevel)
      result.set('progress_percent', progressPercent)
      result.set('manual_level', manualLevel)

      return result
    } catch (e) {
      console.error('获取用户会员信息失败:', e)
      return result
    }
  }

  // 获取当前等级的最低消费金额
  private getCurrentLevelMinAmount(levels: any[], currentLevel: number): number {
    for (let i = 0; i < levels.length; i++) {
      const level = levels[i]
      const levelAny = level as any
      if (levelAny instanceof UTSJSONObject) {
        const levelId = levelAny.getNumber('id') ?? 0
        if (levelId === currentLevel) {
          return levelAny.getNumber('min_amount') ?? 0
        }
      }
    }
    return 0
  }

  // 获取会员等级变更记录
  async getMemberLevelLogs(): Promise<any[]> {
    try {
      const userId = this.getCurrentUserId()
      if (userId == null) {
        const empty: any[] = []
        return empty
      }

      const res = await supa
        .from('ml_member_level_logs')
        .select('*')
        .eq('user_id', userId!)
        .order('created_at', { ascending: false })
        .execute()

      if (res.error != null || res.data == null) {
        const empty: any[] = []
        return empty
      }

      return res.data as any[]
    } catch (e) {
      console.error('获取会员等级变更记录失败:', e)
      const empty: any[] = []
      return empty
    }
  }
}

// 导出单例实例
export const supabaseService = new SupabaseService()

// 默认导出
export default supabaseService
