import React, { forwardRef, useImperativeHandle, useRef } from 'react'
import { Canvas, View } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useUser } from '@/hooks/useUser'
import { generateShareCode } from '@/api/share'

export interface PosterOptions {
  /** 封面图（网络地址或本地路径） */
  cover?: string
  /** 主标题 */
  title: string
  /** 副标题 / 描述 */
  subtitle?: string
  /** 价格（仅展示用） */
  price?: string | number
  /** 小程序码落地页，如 pages/shop/product-detail */
  page?: string
}

export interface SharePosterHandle {
  /** 生成海报，返回临时图片路径，可直接作为分享 imageUrl */
  generate: (opts: PosterOptions) => Promise<string>
}

// 逻辑尺寸（CSS px），实际位图按 dpr 放大
const W = 300
const H = 420
const CANVAS_ID = 'sharePosterCanvas'

const SharePoster = forwardRef<SharePosterHandle>((_, ref) => {
  const { user } = useUser()
  const inviterId = user?.id ?? user?.userId

  const getCanvasNode = (): Promise<any> => {
    return new Promise((resolve, reject) => {
      Taro.createSelectorQuery()
        .select('#' + CANVAS_ID)
        .fields({ node: true, size: true })
        .exec((res) => {
          const node = res && res[0] && res[0].node
          if (node) resolve(node)
          else reject(new Error('未找到 canvas 节点'))
        })
    })
  }

  const loadImage = (canvas: any, src: string): Promise<any> => {
    return new Promise((resolve, reject) => {
      if (!src) return reject(new Error('空图片地址'))
      const img = canvas.createImage()
      img.onload = () => resolve(img)
      img.onerror = (e: any) => reject(e)
      img.src = src
    })
  }

  const drawRoundRect = (
    ctx: any,
    x: number,
    y: number,
    w: number,
    h: number,
    r: number
  ) => {
    ctx.beginPath()
    ctx.moveTo(x + r, y)
    ctx.arcTo(x + w, y, x + w, y + h, r)
    ctx.arcTo(x + w, y + h, x, y + h, r)
    ctx.arcTo(x, y + h, x, y, r)
    ctx.arcTo(x, y, x + w, y, r)
    ctx.closePath()
  }

  const drawRoundImage = (
    ctx: any,
    img: any,
    x: number,
    y: number,
    w: number,
    h: number,
    r: number
  ) => {
    ctx.save()
    drawRoundRect(ctx, x, y, w, h, r)
    ctx.clip()
    ctx.drawImage(img, x, y, w, h)
    ctx.restore()
  }

  /** 文本按宽度换行，最多 maxLines 行 */
  const wrapText = (ctx: any, text: string, maxWidth: number, maxLines: number): string[] => {
    const chars = (text || '').split('')
    const lines: string[] = []
    let line = ''
    for (let i = 0; i < chars.length; i++) {
      const ch = chars[i]
      if (ctx.measureText(line + ch).width > maxWidth && line) {
        lines.push(line)
        line = ch
        if (lines.length === maxLines - 1) break
      } else {
        line += ch
      }
    }
    if (lines.length < maxLines) lines.push(line)
    else if (line) lines[maxLines - 1] = lines[maxLines - 1] + '…'
    return lines
  }

  const generate = async (opts: PosterOptions): Promise<string> => {
    const canvas = await getCanvasNode()
    const ctx = canvas.getContext('2d')
    const dpr = Taro.getSystemInfoSync().pixelRatio || 2
    canvas.width = W * dpr
    canvas.height = H * dpr
    ctx.scale(dpr, dpr)

    // 背景
    ctx.fillStyle = '#ffffff'
    ctx.fillRect(0, 0, W, H)

    // 封面图
    const coverX = 16
    const coverY = 16
    const coverW = W - 32
    const coverH = 200
    if (opts.cover) {
      try {
        const coverImg = await loadImage(canvas, opts.cover)
        drawRoundImage(ctx, coverImg, coverX, coverY, coverW, coverH, 12)
      } catch {
        ctx.fillStyle = '#f2f2f2'
        ctx.fillRect(coverX, coverY, coverW, coverH)
      }
    } else {
      ctx.fillStyle = '#f2f2f2'
      ctx.fillRect(coverX, coverY, coverW, coverH)
    }

    // 主标题
    ctx.fillStyle = '#222222'
    ctx.font = 'bold 16px sans-serif'
    const titleLines = wrapText(ctx, opts.title || '', coverW - 8, 2)
    let ty = coverY + coverH + 30
    titleLines.forEach((ln) => {
      ctx.fillText(ln, coverX, ty)
      ty += 22
    })

    // 价格
    let py = ty + 6
    if (opts.price !== undefined && opts.price !== '' && opts.price !== null) {
      ctx.fillStyle = '#ee0a24'
      ctx.font = 'bold 20px sans-serif'
      ctx.fillText('¥' + opts.price, coverX, py)
      py += 28
    }

    // 副标题
    if (opts.subtitle) {
      ctx.fillStyle = '#999999'
      ctx.font = '12px sans-serif'
      const subLines = wrapText(ctx, opts.subtitle, coverW, 2)
      let sy = py
      subLines.forEach((ln) => {
        ctx.fillText(ln, coverX, sy)
        sy += 16
      })
    }

    // 小程序码
    const codeSize = 86
    const codeX = W - codeSize - 16
    const codeY = H - codeSize - 16
    try {
      const codeUrl = generateShareCode(opts.page || 'pages/index/index', inviterId)
      const dl = await Taro.downloadFile({ url: codeUrl })
      if (dl.statusCode === 200) {
        const codeImg = await loadImage(canvas, dl.tempFilePath)
        drawRoundImage(ctx, codeImg, codeX, codeY, codeSize, codeSize, 8)
        ctx.fillStyle = '#999999'
        ctx.font = '11px sans-serif'
        ctx.fillText('长按识别', codeX, codeY - 6)
      }
    } catch {
      // 小程序码生成失败不影响主海报
    }

    const res = await Taro.canvasToTempFilePath({ canvas })
    return res.tempFilePath
  }

  useImperativeHandle(ref, () => ({ generate }))

  return (
    <View style={{ position: 'fixed', left: -9999, top: 0, zIndex: -1 }}>
      <Canvas type='2d' id={CANVAS_ID} style={{ width: W + 'px', height: H + 'px' }} />
    </View>
  )
})

SharePoster.displayName = 'SharePoster'

export default SharePoster
