/**
 * One-off: convert 企业端操作流程说明.md -> .docx
 */
const fs = require('fs')
const path = require('path')
const {
	Document,
	Packer,
	Paragraph,
	TextRun,
	HeadingLevel,
	Table,
	TableRow,
	TableCell,
	WidthType,
	BorderStyle,
	ImageRun,
	AlignmentType,
	ShadingType
} = require('docx')

const DOC_DIR = path.resolve(__dirname, '..')
const MD_PATH = path.join(DOC_DIR, '企业端操作流程说明.md')
const OUT_PATH = path.join(DOC_DIR, '企业端操作流程说明.docx')

function parseInline(text) {
	const runs = []
	const re = /(\*\*[^*]+\*\*|`[^`]+`)/g
	let last = 0
	let m
	while ((m = re.exec(text)) !== null) {
		if (m.index > last) {
			runs.push(new TextRun({ text: text.slice(last, m.index), size: 21 }))
		}
		const token = m[0]
		if (token.startsWith('**')) {
			runs.push(new TextRun({ text: token.slice(2, -2), bold: true, size: 21 }))
		} else {
			runs.push(new TextRun({ text: token.slice(1, -1), font: 'Consolas', size: 18 }))
		}
		last = m.index + token.length
	}
	if (last < text.length) {
		runs.push(new TextRun({ text: text.slice(last), size: 21 }))
	}
	if (!runs.length) runs.push(new TextRun({ text: text || '', size: 21 }))
	return runs
}

function para(text, opts = {}) {
	return new Paragraph({
		spacing: { after: 120, line: 360 },
		...opts,
		children: typeof text === 'string' ? parseInline(text) : text
	})
}

function heading(text, level) {
	const map = {
		1: HeadingLevel.HEADING_1,
		2: HeadingLevel.HEADING_2,
		3: HeadingLevel.HEADING_3,
		4: HeadingLevel.HEADING_4
	}
	return new Paragraph({
		heading: map[level] || HeadingLevel.HEADING_2,
		spacing: { before: 240, after: 160 },
		children: [new TextRun({ text, bold: true, size: level === 1 ? 32 : level === 2 ? 28 : 24 })]
	})
}

function quotePara(text) {
	return new Paragraph({
		spacing: { after: 100 },
		indent: { left: 240 },
		border: {
			left: { style: BorderStyle.SINGLE, size: 18, color: '93C5FD', space: 8 }
		},
		children: parseInline(text.replace(/^>\s?/, ''))
	})
}

function codePara(line) {
	return new Paragraph({
		spacing: { after: 40 },
		shading: { type: ShadingType.CLEAR, fill: 'F3F4F6' },
		children: [new TextRun({ text: line || ' ', font: 'Consolas', size: 18 })]
	})
}

function cell(text, opts = {}) {
	const isHeader = !!opts.header
	return new TableCell({
		width: { size: opts.width || 3000, type: WidthType.DXA },
		shading: isHeader ? { type: ShadingType.CLEAR, fill: 'DBEAFE' } : undefined,
		borders: {
			top: { style: BorderStyle.SINGLE, size: 4, color: 'CBD5E1' },
			bottom: { style: BorderStyle.SINGLE, size: 4, color: 'CBD5E1' },
			left: { style: BorderStyle.SINGLE, size: 4, color: 'CBD5E1' },
			right: { style: BorderStyle.SINGLE, size: 4, color: 'CBD5E1' }
		},
		children: [
			new Paragraph({
				spacing: { after: 40 },
				children: parseInline(String(text || '').trim()).map((r) => {
					if (isHeader) {
						return new TextRun({ text: r.text || '', bold: true, size: 20 })
					}
					return r
				})
			})
		]
	})
}

function parseTable(lines) {
	const rows = lines
		.filter((l) => !/^\|?\s*-+/.test(l.replace(/\|/g, '').trim() === '' ? 'x' : l) && !/^\|[\s\-:|]+\|$/.test(l))
		.filter((l) => l.includes('|'))
		.map((l) =>
			l
				.replace(/^\|/, '')
				.replace(/\|$/, '')
				.split('|')
				.map((c) => c.trim())
		)
		.filter((cols) => !cols.every((c) => /^:?-+:?$/.test(c)))

	if (!rows.length) return null
	const colCount = Math.max(...rows.map((r) => r.length))
	const width = Math.floor(9000 / colCount)
	return new Table({
		width: { size: 9000, type: WidthType.DXA },
		rows: rows.map((cols, idx) => {
			while (cols.length < colCount) cols.push('')
			return new TableRow({
				children: cols.map((c) => cell(c, { header: idx === 0, width }))
			})
		})
	})
}

async function main() {
	const md = fs.readFileSync(MD_PATH, 'utf8')
	const lines = md.replace(/\r\n/g, '\n').split('\n')
	const children = []
	let i = 0

	while (i < lines.length) {
		const line = lines[i]
		const trimmed = line.trim()

		if (!trimmed) {
			i++
			continue
		}

		if (trimmed === '---') {
			children.push(
				new Paragraph({
					spacing: { before: 120, after: 120 },
					border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: 'E5E7EB', space: 1 } },
					children: []
				})
			)
			i++
			continue
		}

		if (trimmed.startsWith('```')) {
			i++
			while (i < lines.length && !lines[i].trim().startsWith('```')) {
				children.push(codePara(lines[i]))
				i++
			}
			i++ // closing ```
			children.push(new Paragraph({ spacing: { after: 120 }, children: [] }))
			continue
		}

		if (trimmed.startsWith('|')) {
			const tableLines = []
			while (i < lines.length && lines[i].trim().startsWith('|')) {
				tableLines.push(lines[i].trim())
				i++
			}
			const table = parseTable(tableLines)
			if (table) {
				children.push(table)
				children.push(new Paragraph({ spacing: { after: 160 }, children: [] }))
			}
			continue
		}

		const img = trimmed.match(/^!\[([^\]]*)\]\(([^)]+)\)/)
		if (img) {
			const imgPath = path.resolve(DOC_DIR, img[2])
			if (fs.existsSync(imgPath)) {
				const buf = fs.readFileSync(imgPath)
				children.push(
					new Paragraph({
						alignment: AlignmentType.CENTER,
						spacing: { before: 160, after: 160 },
						children: [
							new ImageRun({
								data: buf,
								transformation: { width: 420, height: 560 },
								type: 'png'
							})
						]
					})
				)
				children.push(
					new Paragraph({
						alignment: AlignmentType.CENTER,
						spacing: { after: 200 },
						children: [new TextRun({ text: img[1] || '流程图', italics: true, size: 18, color: '6B7280' })]
					})
				)
			} else {
				children.push(para(`[图片缺失] ${img[1]} (${img[2]})`))
			}
			i++
			continue
		}

		if (trimmed.startsWith('# ')) {
			children.push(heading(trimmed.slice(2), 1))
			i++
			continue
		}
		if (trimmed.startsWith('## ')) {
			children.push(heading(trimmed.slice(3), 2))
			i++
			continue
		}
		if (trimmed.startsWith('### ')) {
			children.push(heading(trimmed.slice(4), 3))
			i++
			continue
		}
		if (trimmed.startsWith('#### ')) {
			children.push(heading(trimmed.slice(5), 4))
			i++
			continue
		}

		if (trimmed.startsWith('>')) {
			while (i < lines.length && lines[i].trim().startsWith('>')) {
				children.push(quotePara(lines[i].trim()))
				i++
			}
			continue
		}

		if (/^[-*]\s+/.test(trimmed)) {
			children.push(
				new Paragraph({
					spacing: { after: 80 },
					indent: { left: 360 },
					children: [
						new TextRun({ text: '• ', size: 21 }),
						...parseInline(trimmed.replace(/^[-*]\s+/, ''))
					]
				})
			)
			i++
			continue
		}

		if (/^\d+\.\s+/.test(trimmed)) {
			const num = trimmed.match(/^(\d+)\.\s+/)[1]
			children.push(
				new Paragraph({
					spacing: { after: 80 },
					indent: { left: 240 },
					children: [
						new TextRun({ text: `${num}. `, size: 21 }),
						...parseInline(trimmed.replace(/^\d+\.\s+/, ''))
					]
				})
			)
			i++
			continue
		}

		if (trimmed.startsWith('*') && trimmed.endsWith('*') && !trimmed.startsWith('**')) {
			children.push(
				new Paragraph({
					spacing: { after: 100 },
					children: [new TextRun({ text: trimmed.replace(/^\*|\*$/g, ''), italics: true, size: 18, color: '6B7280' })]
				})
			)
			i++
			continue
		}

		children.push(para(trimmed))
		i++
	}

	const doc = new Document({
		styles: {
			default: {
				document: {
					styles: [
						{
							id: 'Normal',
							run: { font: 'Microsoft YaHei', size: 21 }
						}
					]
				}
			}
		},
		sections: [
			{
				properties: {
					page: {
						margin: { top: 720, right: 720, bottom: 720, left: 720 }
					}
				},
				children
			}
		]
	})

	const buffer = await Packer.toBuffer(doc)
	fs.writeFileSync(OUT_PATH, buffer)
	console.log('OK ->', OUT_PATH)
	console.log('bytes', buffer.length)
}

main().catch((e) => {
	console.error(e)
	process.exit(1)
})
