/**
 * Soul创业派对 - 阅读页
 * 开发: 卡若
 * 技术支持: 存客宝
 */

const app = getApp()

Page({
  data: {
    // 系统信息
    statusBarHeight: 44,
    navBarHeight: 88,
    
    // 章节信息
    sectionId: '',
    section: null,
    partTitle: '',
    chapterTitle: '',
    
    // 内容
    content: '',
    previewContent: '',
    contentParagraphs: [],
    previewParagraphs: [],
    loading: true,
    
    // 用户状态
    isLoggedIn: false,
    hasFullBook: false,
    canAccess: false,
    purchasedCount: 0,
    
    // 阅读进度
    readingProgress: 0,
    showPaywall: false,
    
    // 上一篇/下一篇
    prevSection: null,
    nextSection: null,
    
    // 价格
    sectionPrice: 1,
    fullBookPrice: 9.9,
    totalSections: 62,
    
    // 弹窗
    showShareModal: false,
    showLoginModal: false,
    showPosterModal: false,
    isPaying: false,
    isGeneratingPoster: false,
    
    // 免费章节
    freeIds: ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']
  },

  onLoad(options) {
    const { id, ref } = options
    
    this.setData({
      statusBarHeight: app.globalData.statusBarHeight,
      navBarHeight: app.globalData.navBarHeight,
      sectionId: id
    })
    
    // 处理推荐码绑定
    if (ref) {
      console.log('[Read] 检测到推荐码:', ref)
      wx.setStorageSync('referral_code', ref)
      app.handleReferralCode({ query: { ref } })
    }
    
    // 加载免费章节配置
    this.loadFreeChaptersConfig()
    
    this.initSection(id)
  },
  
  // 从后端加载免费章节配置
  async loadFreeChaptersConfig() {
    try {
      const res = await app.request('/api/db/config')
      if (res.success && res.freeChapters) {
        this.setData({ freeIds: res.freeChapters })
        console.log('[Read] 加载免费章节配置:', res.freeChapters)
      }
    } catch (e) {
      console.log('[Read] 使用默认免费章节配置')
    }
  },

  onPageScroll(e) {
    // 计算阅读进度
    const query = wx.createSelectorQuery()
    query.select('.page').boundingClientRect()
    query.exec((res) => {
      if (res[0]) {
        const scrollTop = e.scrollTop
        const pageHeight = res[0].height - this.data.statusBarHeight - 200
        const progress = pageHeight > 0 ? Math.min((scrollTop / pageHeight) * 100, 100) : 0
        this.setData({ readingProgress: progress })
      }
    })
  },

  // 初始化章节
  async initSection(id) {
    this.setData({ loading: true })
    
    try {
      // 模拟获取章节数据
      const section = this.getSectionInfo(id)
      const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
      
      const isFree = this.data.freeIds.includes(id)
      const isPurchased = hasFullBook || (purchasedSections && purchasedSections.includes(id))
      const canAccess = isFree || isPurchased
      const purchasedCount = purchasedSections?.length || 0
      
      this.setData({
        section,
        isLoggedIn,
        hasFullBook,
        canAccess,
        purchasedCount,
        showPaywall: !canAccess
      })
      
      // 加载内容
      await this.loadContent(id)
      
      // 获取上一篇/下一篇
      this.loadNavigation(id)
      
    } catch (e) {
      console.error('初始化章节失败:', e)
      wx.showToast({ title: '加载失败', icon: 'none' })
    } finally {
      this.setData({ loading: false })
    }
  },

  // 获取章节信息
  getSectionInfo(id) {
    // 特殊章节
    if (id === 'preface') {
      return { id: 'preface', title: '为什么我每天早上6点在Soul开播?', isFree: true, price: 0 }
    }
    if (id === 'epilogue') {
      return { id: 'epilogue', title: '这本书的真实目的', isFree: true, price: 0 }
    }
    if (id.startsWith('appendix')) {
      const appendixTitles = {
        'appendix-1': 'Soul派对房精选对话',
        'appendix-2': '创业者自检清单',
        'appendix-3': '本书提到的工具和资源'
      }
      return { id, title: appendixTitles[id] || '附录', isFree: true, price: 0 }
    }
    
    // 普通章节
    return {
      id: id,
      title: this.getSectionTitle(id),
      isFree: id === '1.1',
      price: 1
    }
  },

  // 获取章节标题
  getSectionTitle(id) {
    const titles = {
      '1.1': '荷包：电动车出租的被动收入模式',
      '1.2': '老墨:资源整合高手的社交方法',
      '1.3': '笑声背后的MBTI',
      '1.4': '人性的三角结构：利益、情感、价值观',
      '1.5': '沟通差的问题：为什么你说的别人听不懂',
      '2.1': '相亲故事:你以为找的是人,实际是在找模式',
      '2.2': '找工作迷茫者:为什么简历解决不了人生',
      '2.3': '撸运费险:小钱困住大脑的真实心理',
      '2.4': '游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力',
      '2.5': '健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒',
      '3.1': '3000万流水如何跑出来(退税模式解析)',
      '8.1': '流量杠杆:抖音、Soul、飞书',
      '9.14': '大健康私域：一个月150万的70后'
    }
    return titles[id] || `章节 ${id}`
  },

  // 加载内容 - 三级降级方案：API → 本地缓存 → 备用API
  async loadContent(id) {
    const cacheKey = `chapter_${id}`
    
    // 1. 优先从API获取
    try {
      const res = await this.fetchChapterWithTimeout(id, 5000)
      if (res && res.content) {
        this.setChapterContent(res)
        // 成功后缓存到本地
        wx.setStorageSync(cacheKey, res)
        console.log('[Read] 从API加载成功:', id)
        return
      }
    } catch (e) {
      console.warn('[Read] API加载失败，尝试本地缓存:', e.message)
    }
    
    // 2. API失败，尝试从本地缓存读取
    try {
      const cached = wx.getStorageSync(cacheKey)
      if (cached && cached.content) {
        this.setChapterContent(cached)
        console.log('[Read] 从本地缓存加载成功:', id)
        // 后台静默刷新
        this.silentRefresh(id)
        return
      }
    } catch (e) {
      console.warn('[Read] 本地缓存读取失败')
    }
    
    // 3. 都失败，显示加载中并持续重试
    this.setData({
      contentParagraphs: ['章节内容加载中...', '正在尝试连接服务器，请稍候...'],
      previewParagraphs: ['章节内容加载中...']
    })
    
    // 延迟重试（最多3次）
    this.retryLoadContent(id, 3)
  },
  
  // 带超时的章节请求
  fetchChapterWithTimeout(id, timeout = 5000) {
    return new Promise((resolve, reject) => {
      const timer = setTimeout(() => {
        reject(new Error('请求超时'))
      }, timeout)
      
      app.request(`/api/book/chapter/${id}`)
        .then(res => {
          clearTimeout(timer)
          resolve(res)
        })
        .catch(err => {
          clearTimeout(timer)
          reject(err)
        })
    })
  },
  
  // 设置章节内容
  setChapterContent(res) {
    const lines = res.content.split('\n').filter(line => line.trim())
    const previewCount = Math.ceil(lines.length * 0.2)
    
    this.setData({
      content: res.content,
      previewContent: lines.slice(0, previewCount).join('\n'),
      contentParagraphs: lines,
      previewParagraphs: lines.slice(0, previewCount),
      partTitle: res.partTitle || '',
      chapterTitle: res.chapterTitle || ''
    })
  },
  
  // 静默刷新（后台更新缓存）
  async silentRefresh(id) {
    try {
      const res = await this.fetchChapterWithTimeout(id, 10000)
      if (res && res.content) {
        wx.setStorageSync(`chapter_${id}`, res)
        console.log('[Read] 后台缓存更新成功:', id)
      }
    } catch (e) {
      // 静默失败不处理
    }
  },
  
  // 重试加载
  retryLoadContent(id, maxRetries, currentRetry = 0) {
    if (currentRetry >= maxRetries) {
      this.setData({
        contentParagraphs: ['内容加载失败', '请检查网络连接后下拉刷新重试'],
        previewParagraphs: ['内容加载失败']
      })
      return
    }
    
    setTimeout(async () => {
      try {
        const res = await this.fetchChapterWithTimeout(id, 8000)
        if (res && res.content) {
          this.setChapterContent(res)
          wx.setStorageSync(`chapter_${id}`, res)
          console.log('[Read] 重试成功:', id, '第', currentRetry + 1, '次')
          return
        }
      } catch (e) {
        console.warn('[Read] 重试失败，继续重试:', currentRetry + 1)
      }
      this.retryLoadContent(id, maxRetries, currentRetry + 1)
    }, 2000 * (currentRetry + 1))
  },


  // 加载导航
  loadNavigation(id) {
    const sectionOrder = [
      'preface', '1.1', '1.2', '1.3', '1.4', '1.5',
      '2.1', '2.2', '2.3', '2.4', '2.5',
      '3.1', '3.2', '3.3', '3.4',
      '4.1', '4.2', '4.3', '4.4', '4.5',
      '5.1', '5.2', '5.3', '5.4', '5.5',
      '6.1', '6.2', '6.3', '6.4',
      '7.1', '7.2', '7.3', '7.4', '7.5',
      '8.1', '8.2', '8.3', '8.4', '8.5', '8.6',
      '9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '9.7', '9.8', '9.9', '9.10', '9.11', '9.12', '9.13', '9.14',
      '10.1', '10.2', '10.3', '10.4',
      '11.1', '11.2', '11.3', '11.4', '11.5',
      'epilogue'
    ]
    
    const currentIndex = sectionOrder.indexOf(id)
    const prevId = currentIndex > 0 ? sectionOrder[currentIndex - 1] : null
    const nextId = currentIndex < sectionOrder.length - 1 ? sectionOrder[currentIndex + 1] : null
    
    this.setData({
      prevSection: prevId ? { id: prevId, title: this.getSectionTitle(prevId) } : null,
      nextSection: nextId ? { id: nextId, title: this.getSectionTitle(nextId) } : null
    })
  },

  // 返回
  goBack() {
    wx.navigateBack({
      fail: () => wx.switchTab({ url: '/pages/chapters/chapters' })
    })
  },

  // 分享弹窗
  showShare() {
    this.setData({ showShareModal: true })
  },

  closeShareModal() {
    this.setData({ showShareModal: false })
  },

  // 复制链接
  copyLink() {
    const userInfo = app.globalData.userInfo
    const referralCode = userInfo?.referralCode || ''
    const shareUrl = `https://soul.quwanzhi.com/read/${this.data.sectionId}${referralCode ? '?ref=' + referralCode : ''}`
    
    wx.setClipboardData({
      data: shareUrl,
      success: () => {
        wx.showToast({ title: '链接已复制', icon: 'success' })
        this.setData({ showShareModal: false })
      }
    })
  },

  // 复制分享文案（朋友圈风格）
  copyShareText() {
    const { section } = this.data
    
    const shareText = `🔥 刚看完这篇《${section?.title || 'Soul创业派对'}》，太上头了！

62个真实商业案例，每个都是从0到1的实战经验。私域运营、资源整合、商业变现，干货满满。

推荐给正在创业或想创业的朋友，搜"Soul创业派对"小程序就能看！

#创业派对 #私域运营 #商业案例`
    
    wx.setClipboardData({
      data: shareText,
      success: () => {
        wx.showToast({ title: '文案已复制', icon: 'success' })
      }
    })
  },

  // 分享到微信 - 自动带分享人ID
  onShareAppMessage() {
    const { section, sectionId } = this.data
    const userInfo = app.globalData.userInfo
    const referralCode = userInfo?.referralCode || wx.getStorageSync('referralCode') || ''
    
    // 分享标题优化
    const shareTitle = section?.title 
      ? `📚 ${section.title.length > 20 ? section.title.slice(0, 20) + '...' : section.title}`
      : '📚 Soul创业派对 - 真实商业故事'
    
    return {
      title: shareTitle,
      path: `/pages/read/read?id=${sectionId}${referralCode ? '&ref=' + referralCode : ''}`,
      imageUrl: '/assets/share-cover.png' // 可配置分享封面图
    }
  },
  
  // 分享到朋友圈
  onShareTimeline() {
    const { section, sectionId } = this.data
    const userInfo = app.globalData.userInfo
    const referralCode = userInfo?.referralCode || ''
    
    return {
      title: `${section?.title || 'Soul创业派对'} - 来自派对房的真实故事`,
      query: `id=${sectionId}${referralCode ? '&ref=' + referralCode : ''}`
    }
  },

  // 显示登录弹窗
  showLoginModal() {
    this.setData({ showLoginModal: true })
  },

  closeLoginModal() {
    this.setData({ showLoginModal: false })
  },

  // 微信登录
  async handleWechatLogin() {
    try {
      const result = await app.login()
      if (result) {
        this.setData({ showLoginModal: false })
        this.initSection(this.data.sectionId)
        wx.showToast({ title: '登录成功', icon: 'success' })
      }
    } catch (e) {
      wx.showToast({ title: '登录失败', icon: 'none' })
    }
  },

  // 手机号登录
  async handlePhoneLogin(e) {
    if (!e.detail.code) {
      return this.handleWechatLogin()
    }
    
    try {
      const result = await app.loginWithPhone(e.detail.code)
      if (result) {
        this.setData({ showLoginModal: false })
        this.initSection(this.data.sectionId)
        wx.showToast({ title: '登录成功', icon: 'success' })
      }
    } catch (e) {
      wx.showToast({ title: '登录失败', icon: 'none' })
    }
  },

  // 购买章节 - 直接调起支付
  async handlePurchaseSection() {
    console.log('[Pay] 点击购买章节按钮')
    wx.showLoading({ title: '处理中...', mask: true })
    
    if (!this.data.isLoggedIn) {
      wx.hideLoading()
      console.log('[Pay] 用户未登录，显示登录弹窗')
      this.setData({ showLoginModal: true })
      return
    }
    
    const price = this.data.section?.price || 1
    console.log('[Pay] 开始支付流程:', { sectionId: this.data.sectionId, price })
    wx.hideLoading()
    await this.processPayment('section', this.data.sectionId, price)
  },

  // 购买全书 - 直接调起支付
  async handlePurchaseFullBook() {
    console.log('[Pay] 点击购买全书按钮')
    wx.showLoading({ title: '处理中...', mask: true })
    
    if (!this.data.isLoggedIn) {
      wx.hideLoading()
      console.log('[Pay] 用户未登录，显示登录弹窗')
      this.setData({ showLoginModal: true })
      return
    }
    
    console.log('[Pay] 开始支付流程: 全书', { price: this.data.fullBookPrice })
    wx.hideLoading()
    await this.processPayment('fullbook', null, this.data.fullBookPrice)
  },

  // 处理支付 - 调用真实微信支付接口
  async processPayment(type, sectionId, amount) {
    console.log('[Pay] processPayment开始:', { type, sectionId, amount })
    
    // 检查金额是否有效
    if (!amount || amount <= 0) {
      console.error('[Pay] 金额无效:', amount)
      wx.showToast({ title: '价格信息错误', icon: 'none' })
      return
    }
    
    // 检查是否已购买（避免重复购买）
    if (type === 'section' && sectionId) {
      const purchasedSections = app.globalData.purchasedSections || []
      if (purchasedSections.includes(sectionId)) {
        wx.showToast({ title: '已购买过此章节', icon: 'none' })
        return
      }
    }
    
    if (type === 'fullbook' && app.globalData.hasFullBook) {
      wx.showToast({ title: '已购买全书', icon: 'none' })
      return
    }
    
    this.setData({ isPaying: true })
    wx.showLoading({ title: '正在发起支付...', mask: true })
    
    try {
      // 1. 先获取openId (支付必需)
      let openId = app.globalData.openId || wx.getStorageSync('openId')
      
      if (!openId) {
        console.log('[Pay] 需要先获取openId，尝试静默获取')
        wx.showLoading({ title: '获取支付凭证...', mask: true })
        openId = await app.getOpenId()
        
        if (!openId) {
          // openId获取失败，但已登录用户可以使用用户ID替代
          if (app.globalData.isLoggedIn && app.globalData.userInfo?.id) {
            console.log('[Pay] 使用用户ID作为替代')
            openId = app.globalData.userInfo.id
          } else {
            wx.hideLoading()
            wx.showModal({
              title: '提示',
              content: '需要登录后才能支付，请先登录',
              showCancel: false
            })
            this.setData({ showLoginModal: true, isPaying: false })
            return
          }
        }
      }
      
      console.log('[Pay] 开始创建订单:', { type, sectionId, amount, openId: openId.slice(0, 10) + '...' })
      wx.showLoading({ title: '创建订单中...', mask: true })
      
      // 2. 调用后端创建预支付订单
      let paymentData = null
      
      try {
        // 获取章节完整名称用于支付描述
        const sectionTitle = this.data.section?.title || sectionId
        const description = type === 'fullbook' 
          ? '《一场Soul的创业实验》全书' 
          : `章节${sectionId}-${sectionTitle.length > 20 ? sectionTitle.slice(0, 20) + '...' : sectionTitle}`
        
        const res = await app.request('/api/miniprogram/pay', {
          method: 'POST',
          data: {
            openId,
            productType: type,
            productId: sectionId,
            amount,
            description,
            userId: app.globalData.userInfo?.id || ''
          }
        })
        
        console.log('[Pay] 创建订单响应:', res)
        
        if (res.success && res.data?.payParams) {
          paymentData = res.data.payParams
          console.log('[Pay] 获取支付参数成功:', paymentData)
        } else {
          throw new Error(res.error || res.message || '创建订单失败')
        }
      } catch (apiError) {
        console.error('[Pay] API创建订单失败:', apiError)
        wx.hideLoading()
        // 支付接口失败时，显示客服联系方式
        wx.showModal({
          title: '支付通道维护中',
          content: '微信支付正在审核中，请添加客服微信（28533368）手动购买，感谢理解！',
          confirmText: '复制微信号',
          cancelText: '稍后再说',
          success: (res) => {
            if (res.confirm) {
              wx.setClipboardData({
                data: '28533368',
                success: () => {
                  wx.showToast({ title: '微信号已复制', icon: 'success' })
                }
              })
            }
          }
        })
        this.setData({ isPaying: false })
        return
      }
      
      // 3. 调用微信支付
      wx.hideLoading()
      console.log('[Pay] 调起微信支付, paymentData:', paymentData)
      
      try {
        await this.callWechatPay(paymentData)
        
        // 4. 支付成功，更新本地数据
        console.log('[Pay] 微信支付成功!')
        this.mockPaymentSuccess(type, sectionId)
        wx.showToast({ title: '购买成功', icon: 'success' })
        
        // 5. 刷新页面
        this.initSection(this.data.sectionId)
      } catch (payErr) {
        console.error('[Pay] 微信支付调起失败:', payErr)
        if (payErr.errMsg && payErr.errMsg.includes('cancel')) {
          wx.showToast({ title: '已取消支付', icon: 'none' })
        } else if (payErr.errMsg && payErr.errMsg.includes('requestPayment:fail')) {
          // 支付失败，可能是参数错误或权限问题
          wx.showModal({
            title: '支付失败',
            content: '微信支付暂不可用，请添加客服微信（28533368）手动购买',
            confirmText: '复制微信号',
            cancelText: '取消',
            success: (res) => {
              if (res.confirm) {
                wx.setClipboardData({
                  data: '28533368',
                  success: () => wx.showToast({ title: '微信号已复制', icon: 'success' })
                })
              }
            }
          })
        } else {
          wx.showToast({ title: payErr.errMsg || '支付失败', icon: 'none' })
        }
      }
      
    } catch (e) {
      console.error('[Pay] 支付流程异常:', e)
      wx.hideLoading()
      wx.showToast({ title: '支付出错，请重试', icon: 'none' })
    } finally {
      this.setData({ isPaying: false })
    }
  },

  // 模拟支付成功
  mockPaymentSuccess(type, sectionId) {
    if (type === 'fullbook') {
      app.globalData.hasFullBook = true
      const userInfo = app.globalData.userInfo || {}
      userInfo.hasFullBook = true
      app.globalData.userInfo = userInfo
      wx.setStorageSync('userInfo', userInfo)
    } else if (sectionId) {
      const purchasedSections = app.globalData.purchasedSections || []
      if (!purchasedSections.includes(sectionId)) {
        purchasedSections.push(sectionId)
        app.globalData.purchasedSections = purchasedSections
        
        const userInfo = app.globalData.userInfo || {}
        userInfo.purchasedSections = purchasedSections
        app.globalData.userInfo = userInfo
        wx.setStorageSync('userInfo', userInfo)
      }
    }
  },

  // 调用微信支付
  callWechatPay(paymentData) {
    return new Promise((resolve, reject) => {
      wx.requestPayment({
        timeStamp: paymentData.timeStamp,
        nonceStr: paymentData.nonceStr,
        package: paymentData.package,
        signType: paymentData.signType || 'MD5',
        paySign: paymentData.paySign,
        success: resolve,
        fail: reject
      })
    })
  },

  // 跳转到上一篇
  goToPrev() {
    if (this.data.prevSection) {
      wx.redirectTo({ url: `/pages/read/read?id=${this.data.prevSection.id}` })
    }
  },

  // 跳转到下一篇
  goToNext() {
    if (this.data.nextSection) {
      wx.redirectTo({ url: `/pages/read/read?id=${this.data.nextSection.id}` })
    }
  },

  // 跳转到推广中心
  goToReferral() {
    wx.navigateTo({ url: '/pages/referral/referral' })
  },

  // 生成海报
  async generatePoster() {
    wx.showLoading({ title: '生成中...' })
    this.setData({ showPosterModal: true, isGeneratingPoster: true })
    
    try {
      const ctx = wx.createCanvasContext('posterCanvas', this)
      const { section, contentParagraphs, sectionId } = this.data
      const userInfo = app.globalData.userInfo
      const userId = userInfo?.id || ''
      
      // 获取小程序码（带推荐人参数）
      let qrcodeImage = null
      try {
        const scene = userId ? `id=${sectionId}&ref=${userId.slice(0,10)}` : `id=${sectionId}`
        const qrRes = await app.request('/api/miniprogram/qrcode', {
          method: 'POST',
          data: { scene, page: 'pages/read/read', width: 280 }
        })
        if (qrRes.success && qrRes.image) {
          qrcodeImage = qrRes.image
        }
      } catch (e) {
        console.log('[Poster] 获取小程序码失败，使用占位符')
      }
      
      // 海报尺寸 300x450
      const width = 300
      const height = 450
      
      // 背景渐变
      const grd = ctx.createLinearGradient(0, 0, 0, height)
      grd.addColorStop(0, '#1a1a2e')
      grd.addColorStop(1, '#16213e')
      ctx.setFillStyle(grd)
      ctx.fillRect(0, 0, width, height)
      
      // 顶部装饰条
      ctx.setFillStyle('#00CED1')
      ctx.fillRect(0, 0, width, 4)
      
      // 标题区域
      ctx.setFillStyle('#ffffff')
      ctx.setFontSize(14)
      ctx.fillText('📚 Soul创业派对', 20, 35)
      
      // 章节标题
      ctx.setFontSize(18)
      ctx.setFillStyle('#ffffff')
      const title = section?.title || '精彩内容'
      const titleLines = this.wrapText(ctx, title, width - 40, 18)
      let y = 70
      titleLines.forEach(line => {
        ctx.fillText(line, 20, y)
        y += 26
      })
      
      // 分隔线
      ctx.setStrokeStyle('rgba(255,255,255,0.1)')
      ctx.beginPath()
      ctx.moveTo(20, y + 10)
      ctx.lineTo(width - 20, y + 10)
      ctx.stroke()
      
      // 内容摘要
      ctx.setFontSize(12)
      ctx.setFillStyle('rgba(255,255,255,0.8)')
      y += 30
      const summary = contentParagraphs.slice(0, 3).join(' ').slice(0, 150) + '...'
      const summaryLines = this.wrapText(ctx, summary, width - 40, 12)
      summaryLines.slice(0, 6).forEach(line => {
        ctx.fillText(line, 20, y)
        y += 20
      })
      
      // 底部区域背景
      ctx.setFillStyle('rgba(0,206,209,0.1)')
      ctx.fillRect(0, height - 100, width, 100)
      
      // 左侧提示文字
      ctx.setFillStyle('#ffffff')
      ctx.setFontSize(13)
      ctx.fillText('长按识别小程序码', 20, height - 60)
      ctx.setFillStyle('rgba(255,255,255,0.6)')
      ctx.setFontSize(11)
      ctx.fillText('长按小程序码阅读全文', 20, height - 38)
      
      // 绘制小程序码或占位符
      const drawQRCode = () => {
        return new Promise((resolve) => {
          if (qrcodeImage) {
            // 下载base64图片并绘制
            const fs = wx.getFileSystemManager()
            const filePath = `${wx.env.USER_DATA_PATH}/qrcode_${Date.now()}.png`
            const base64Data = qrcodeImage.replace(/^data:image\/\w+;base64,/, '')
            
            fs.writeFile({
              filePath,
              data: base64Data,
              encoding: 'base64',
              success: () => {
                ctx.drawImage(filePath, width - 85, height - 85, 70, 70)
                resolve()
              },
              fail: () => {
                this.drawQRPlaceholder(ctx, width, height)
                resolve()
              }
            })
          } else {
            this.drawQRPlaceholder(ctx, width, height)
            resolve()
          }
        })
      }
      
      await drawQRCode()
      
      ctx.draw(true, () => {
        wx.hideLoading()
        this.setData({ isGeneratingPoster: false })
      })
    } catch (e) {
      console.error('生成海报失败:', e)
      wx.hideLoading()
      wx.showToast({ title: '生成失败', icon: 'none' })
      this.setData({ showPosterModal: false, isGeneratingPoster: false })
    }
  },
  
  // 绘制小程序码占位符
  drawQRPlaceholder(ctx, width, height) {
    ctx.setFillStyle('#ffffff')
    ctx.beginPath()
    ctx.arc(width - 50, height - 50, 35, 0, Math.PI * 2)
    ctx.fill()
    ctx.setFillStyle('#00CED1')
    ctx.setFontSize(9)
    ctx.fillText('扫码', width - 57, height - 52)
    ctx.fillText('阅读', width - 57, height - 40)
  },
  
  // 文字换行处理
  wrapText(ctx, text, maxWidth, fontSize) {
    const lines = []
    let line = ''
    for (let i = 0; i < text.length; i++) {
      const testLine = line + text[i]
      const metrics = ctx.measureText(testLine)
      if (metrics.width > maxWidth && line) {
        lines.push(line)
        line = text[i]
      } else {
        line = testLine
      }
    }
    if (line) lines.push(line)
    return lines
  },
  
  // 关闭海报弹窗
  closePosterModal() {
    this.setData({ showPosterModal: false })
  },
  
  // 保存海报到相册
  savePoster() {
    wx.canvasToTempFilePath({
      canvasId: 'posterCanvas',
      success: (res) => {
        wx.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
          success: () => {
            wx.showToast({ title: '已保存到相册', icon: 'success' })
            this.setData({ showPosterModal: false })
          },
          fail: (err) => {
            if (err.errMsg.includes('auth deny')) {
              wx.showModal({
                title: '提示',
                content: '需要相册权限才能保存海报',
                confirmText: '去设置',
                success: (res) => {
                  if (res.confirm) {
                    wx.openSetting()
                  }
                }
              })
            } else {
              wx.showToast({ title: '保存失败', icon: 'none' })
            }
          }
        })
      },
      fail: () => {
        wx.showToast({ title: '生成图片失败', icon: 'none' })
      }
    }, this)
  },

  // 阻止冒泡
  stopPropagation() {}
})
