/**
 * 名片海报生成工具
 * 使用 Canvas 2D 绘制名片海报
 * 名片底部添加名片码（二维码）
 */

const W = 750
const H = 600
const PADDING = 40

const roundRect = (ctx, x, y, w, h, r) => {
	ctx.beginPath()
	ctx.moveTo(x + r, y)
	ctx.lineTo(x + w - r, y)
	ctx.quadraticCurveTo(x + w, y, x + w, y + r)
	ctx.lineTo(x + w, y + h - r)
	ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h)
	ctx.lineTo(x + r, y + h)
	ctx.quadraticCurveTo(x, y + h, x, y + h - r)
	ctx.lineTo(x, y + r)
	ctx.quadraticCurveTo(x, y, x + r, y)
	ctx.closePath()
}

/**
 * 创建图片对象 - 必须使用 canvas.createImage()
 * 微信小程序 Canvas 2D 中不能用 uni.createImage()
 */
const createCanvasImage = (canvas, src) => {
	return new Promise((resolve) => {
		if (!src) return resolve(null)
		const img = canvas.createImage()
		img.onload = () => resolve(img)
		img.onerror = () => {
			console.warn('图片加载失败:', src)
			resolve(null)
		}
		img.src = src
	})
}

const downloadImage = async (url) => {
	try {
		if (!url || !url.startsWith('http')) return url
		const res = await uni.downloadFile({ url })
		if (res.statusCode === 200) return res.tempFilePath
		return null
	} catch { return null }
}

/**
 * 将图片资源转换为Canvas可用的临时路径
 */
const resolveImageSrc = async (src) => {
	if (!src) return null
	if (src.startsWith('http')) {
		try {
			const res = await uni.downloadFile({ url: src })
			if (res.statusCode === 200) return res.tempFilePath
			return null
		} catch { return null }
	}
	if (src.startsWith('/') || src.startsWith('.')) {
		try {
			const res = await uni.getImageInfo({ src })
			return res.path
		} catch { return null }
	}
	return src
}

/**
 * base64 二维码转临时文件路径
 */
const qrBase64ToTempFile = async (base64Data) => {
	if (!base64Data) return null
	return new Promise((resolve) => {
		try {
			const pureBase64 = base64Data.replace(/^data:image\/\w+;base64,/, '')
			const fileName = `${Date.now()}_qrcode.png`
			const filePath = `${wx.env.USER_DATA_PATH}/${fileName}`
			const fs = uni.getFileSystemManager()
			fs.writeFile({
				filePath,
				data: pureBase64,
				encoding: 'base64',
				success: () => resolve(filePath),
				fail: () => resolve(null)
			})
		} catch {
			resolve(null)
		}
	})
}

const drawCircleAvatar = (ctx, img, cx, cy, r) => {
	ctx.save()
	ctx.beginPath()
	ctx.arc(cx, cy, r, 0, Math.PI * 2)
	ctx.clip()
	if (img) ctx.drawImage(img, cx - r, cy - r, r * 2, r * 2)
	ctx.restore()
}

const drawAvatarFallback = (ctx, cardInfo, cx, cy, r) => {
	ctx.save()
	ctx.beginPath()
	ctx.arc(cx, cy, r, 0, Math.PI * 2)
	ctx.fillStyle = '#4080FF'
	ctx.fill()
	ctx.strokeStyle = 'rgba(255,255,255,0.6)'
	ctx.lineWidth = 4
	ctx.stroke()
	const initial = cardInfo.nickName ? cardInfo.nickName.charAt(0) : '?'
	ctx.fillStyle = '#FFFFFF'
	ctx.font = `bold ${r}px sans-serif`
	ctx.textAlign = 'center'
	ctx.textBaseline = 'middle'
	ctx.fillText(initial, cx, cy)
	ctx.restore()
}

const drawContactRow = (ctx, emoji, text, x, y) => {
	if (!text) return
	ctx.save()
	ctx.beginPath()
	ctx.arc(x + 20, y + 20, 20, 0, Math.PI * 2)
	ctx.fillStyle = 'rgba(64, 128, 255, 0.08)'
	ctx.fill()
	ctx.restore()
	ctx.font = '22px sans-serif'
	ctx.textAlign = 'center'
	ctx.textBaseline = 'middle'
	ctx.fillText(emoji, x + 20, y + 20)
	ctx.font = '26px sans-serif'
	ctx.textAlign = 'left'
	ctx.textBaseline = 'middle'
	ctx.fillStyle = '#555555'
	const textMaxWidth = 480
	const textX = x + 52
	if (ctx.measureText(text).width > textMaxWidth) {
		ctx.textBaseline = 'top'
		const lineY = y + 10
		fillTextWrap(ctx, text, textX, lineY, textMaxWidth, 40, 'left')
	} else {
		ctx.fillText(text, textX, y + 20)
	}
}

const fillTextWrap = (ctx, text, x, y, maxWidth, lineHeight, align = 'left') => {
	if (!text) return y
	ctx.textAlign = align
	ctx.textBaseline = 'top'
	const chars = text.split('')
	let line = '', cy = y
	for (let i = 0; i < chars.length; i++) {
		const test = line + chars[i]
		if (ctx.measureText(test).width > maxWidth && i > 0) {
			ctx.fillText(line, x, cy)
			line = chars[i]
			cy += lineHeight
		} else {
			line = test
		}
	}
	ctx.fillText(line, x, cy)
	return cy + lineHeight
}

export const generateCardPoster = async (cardInfo = {}, qrInfo = {}) => {
	return new Promise((resolve, reject) => {
		const query = uni.createSelectorQuery()
		query.select('#posterCanvas')
			.fields({ node: true, size: true })
			.exec(async (res) => {
				if (!res || !res[0]) {
					reject(new Error('Canvas 节点未找到'))
					return
				}

				const canvas = res[0].node
				const ctx = canvas.getContext('2d')
				const dpr = uni.getSystemInfoSync().pixelRatio || 2
				canvas.width = W * dpr
				canvas.height = H * dpr
				ctx.scale(dpr, dpr)

				// ===== 1. 渐变背景 =====
				const bgGrad = ctx.createLinearGradient(0, 0, 0, H)
				bgGrad.addColorStop(0, '#4A90E2')
				bgGrad.addColorStop(0.5, '#6FB3F2')
				bgGrad.addColorStop(1, '#B0E0E6')
				ctx.fillStyle = bgGrad
				ctx.fillRect(0, 0, W, H)

				// ===== 2. 装饰圆点 =====
				ctx.fillStyle = 'rgba(255,255,255,0.10)'
				ctx.beginPath(); ctx.arc(620, 160, 100, 0, Math.PI * 2); ctx.fill()
				ctx.beginPath(); ctx.arc(680, 320, 60, 0, Math.PI * 2); ctx.fill()
				ctx.beginPath(); ctx.arc(-20, 640, 80, 0, Math.PI * 2); ctx.fill()

				// ===== 3. 白色卡片 =====
				const cardX = PADDING, cardY = 60
				const cardW = W - PADDING * 2, cardH = 480
				ctx.save()
				ctx.shadowColor = 'rgba(0,0,0,0.08)'
				ctx.shadowBlur = 24
				ctx.shadowOffsetY = 6
				ctx.fillStyle = '#FFFFFF'
				roundRect(ctx, cardX, cardY, cardW, cardH, 24)
				ctx.fill()
				ctx.restore()

				// ===== 4. 内部名片卡片 =====
				const innerX = cardX + 32
				const innerY = cardY + 32
				const innerW = cardW - 64
				const innerH = cardH - 64
				ctx.save()
				ctx.shadowColor = 'rgba(0,0,0,0.05)'
				ctx.shadowBlur = 16
				ctx.shadowOffsetY = 3
				ctx.fillStyle = '#FFFFFF'
				roundRect(ctx, innerX, innerY, innerW, innerH, 16)
				ctx.fill()
				ctx.restore()

				// 背景图
				try {
					const bgSrc = await resolveImageSrc('/static/image/home/usecard-bg.png')
					if (bgSrc) {
						const cardBg = await createCanvasImage(canvas, bgSrc)
						if (cardBg) {
							ctx.save()
							roundRect(ctx, innerX, innerY, innerW, innerH, 16)
							ctx.clip()
							ctx.drawImage(cardBg, innerX, innerY, innerW, innerH)
							ctx.restore()
						}
					}
				} catch (e) {
					console.warn('加载名片背景图失败:', e)
				}

				// ===== 5. 头像（右上角）=====
				const avatarCx = innerX + innerW - 100
				const avatarCy = innerY + 70
				const avatarR = 60
				ctx.save()
				ctx.beginPath()
				ctx.arc(avatarCx, avatarCy, avatarR + 4, 0, Math.PI * 2)
				ctx.fillStyle = 'rgba(255,255,255,0.5)'
				ctx.fill()
				ctx.restore()

				let avatarImg = null
				if (cardInfo.avatar) {
					const localPath = await downloadImage(cardInfo.avatar)
					avatarImg = await createCanvasImage(canvas, localPath)
				}
				if (avatarImg) {
					drawCircleAvatar(ctx, avatarImg, avatarCx, avatarCy, avatarR)
				} else {
					drawAvatarFallback(ctx, cardInfo, avatarCx, avatarCy, avatarR)
				}

				// ===== 6. 姓名 + 职位 + 公司 =====
				const nameX = innerX + 44
				const nameY = innerY + 50

				ctx.fillStyle = '#202020'
				ctx.font = 'bold 44px sans-serif'
				ctx.textAlign = 'left'
				ctx.textBaseline = 'top'
				const name = cardInfo.nickName || '用户'
				ctx.fillText(name, nameX, nameY)
				const nameW = ctx.measureText(name).width

				if (cardInfo.postName) {
					const tagX = nameX + nameW + 14
					ctx.font = '22px sans-serif'
					const tagTextW = ctx.measureText(cardInfo.postName).width
					const tagW = tagTextW + 26
					ctx.fillStyle = 'rgba(68, 110, 255, 0.10)'
					roundRect(ctx, tagX, nameY + 6, tagW, 34, 8)
					ctx.fill()
					ctx.fillStyle = '#446EFF'
					ctx.textAlign = 'left'
					ctx.textBaseline = 'top'
					ctx.fillText(cardInfo.postName, tagX + 13, nameY + 11)
				}

				// 公司名称
				ctx.fillStyle = '#666666'
				ctx.font = '26px sans-serif'
				ctx.textAlign = 'left'
				ctx.textBaseline = 'top'
				const companyMaxW = innerW - 200
				const companyName = cardInfo.companyName || '公司名称'
				const companyX = innerX + 44
				const companyY = nameY + 60
				const companyEndY = fillTextWrap(ctx, companyName, companyX, companyY, companyMaxW, 36, 'left')

				// ===== 7. 联系方式 =====
				const contactY = Math.max(companyEndY + 24, innerY + 160)
				const contactX = innerX + 44
				const contactGap = 60

				ctx.strokeStyle = '#EEEEEE'
				ctx.lineWidth = 1
				ctx.beginPath()
				ctx.moveTo(contactX, contactY)
				ctx.lineTo(innerX + innerW - 44, contactY)
				ctx.stroke()

				drawContactRow(ctx, '📞', cardInfo.phonenumber, contactX, contactY + 20)
				drawContactRow(ctx, '✉', cardInfo.email, contactX, contactY + 20 + contactGap)
				drawContactRow(ctx, '📍', cardInfo.companyAddress, contactX, contactY + 20 + contactGap * 2)

				// ===== 8. 导出 =====
				setTimeout(() => {
					uni.canvasToTempFilePath({
						canvas,
						success: (res) => resolve(res.tempFilePath),
						fail: (err) => reject(err)
					})
				}, 600)
			})
	})
}

export const savePosterToAlbum = (tempFilePath) => {
	return new Promise((resolve, reject) => {
		uni.authorize({
			scope: 'scope.writePhotosAlbum',
			success: () => {
				uni.saveImageToPhotosAlbum({
					filePath: tempFilePath,
					success: () => resolve(),
					fail: (err) => reject(err)
				})
			},
			fail: () => {
				uni.showModal({
					title: '提示',
					content: '需要授权相册权限才能保存名片',
					confirmText: '去设置',
					success: (res) => {
						if (res.confirm) uni.openSetting({})
						reject(new Error('未授权'))
					}
				})
			}
		})
	})
}

export default { generateCardPoster, savePosterToAlbum }
