// plugin/vue-renderer/renderer/render-compile.js
// idea taken from: https://lachlan-miller.me/articles/vue-3-pdf-customer-renderer

import fs from 'fs'
import process from 'process'
import { exec } from 'node:child_process'
import { sourcePath, newComponentPath, copyFiles } from './copy-files.js' // creates new component folder and copies common files
import { provide, defineComponent, compileTemplate, createRenderer } from '../vuelib.js' // 'vue'
import { newDocument } from './element.js'
import { createNodeOps } from './nodeOps.js'
import { setDefaultVuePath, compileVueFile } from './compileVueFile.js'

const vapor = false
let elementJson
if (vapor) {
	elementJson = fs.readFileSync('./element-arr-vapor.json', 'utf8')
} else {
	elementJson = fs.readFileSync('./element-arr.json', 'utf8')
}

let perf // = performance
if (typeof performance === 'undefined') {
	perf = {
		now() {
			return 0
		}
	}
} else {
	perf = performance
}
console.log('Current directory:', process.cwd())
let startTime = perf.now()
if (fs.existsSync('../component2')) {
	console.warn('deleting ../component2 -directory before running this script')
	fs.rmSync('../component2', { recursive: true, force: true }) // old node: fs.rmdirSync
}
console.warn('To make a clean copy, please remove ../core -directory before running this script')
copyFiles()
const srcPath = sourcePath()
const elementArr = JSON.parse(elementJson).element
const compiledComponent = []
const ssr = false
const sourceMap = false
setDefaultVuePath('../vuelib.js')

// compileVueFile('/Users/pasi/nc/nc-plugin/preference/form/nc/', 'nc-list-form/nc-list-form.html', newComponentPath, ssr)
let runStartTime = perf.now()
elementArr.forEach(fileName => {
	compiledComponent.push(compileVueFile(srcPath, fileName, newComponentPath, ssr, sourceMap, vapor))
})
Promise.allSettled(compiledComponent).then(ret => {
	const componentArr = ret.reduce((arr, item) => {
		if (item.status === 'fulfilled') {
			item = item.value
			if (!item.default.render) {
				// console.error(`component ${item.default.name} has render -tag in default export`)
				console.error(`component ${item.default.name} does not have render -tag in default export`)
			}
			if (item.ssrRender) {
				item.default.ssrRender = item.ssrRender
			} else {
				item.default.render = item.render
			}
			arr.push(item.default)
			return arr
		} else {
			console.error('compileVueFile failed, error: ', item.reason)
		}
	}, [])
	run(componentArr)
})

const replaceVShow = new RegExp('v-show=', 'g')
function run(componentArr) {
	const componentCreationTime = perf.now() - runStartTime
	runStartTime = perf.now()
	const stateRec = JSON.parse(fs.readFileSync('./state.json', 'utf8'))
	import('../core/nc-state.js').then(module => {
		// we need dynamic import because ../core/nc-state.js will be copiend from source and does not exist on file start
		let state = module.newState('nc-render', stateRec)
		state.rec.printing = true
		let html = fs.readFileSync('./page.html', 'utf8')
		html = html.replace(replaceVShow, 'v-if=')

		const App = defineComponent({
			name: 'NcRender',
			// components: comp, // create later by app.component(), components must be in app, here is not enugh
			setup() {
				provide('state', state)
				// return Object.assign({ style: appStyle }, toRefs(state)) // this is old-browser compatible version of '...state'
				return { ...state, state } // ...toRefs(state) if state is reactive
			},
			render: compileTemplate(`${html}`)
		})

		function createApp(...args) {
			// Modelled after https://github.com/vuejs/vue-next/blob/master/packages/runtime-dom/src/index.ts#L61
			const nodeMap = []
			const nodeOps = createNodeOps(nodeMap) // createNodeOps generates nodeMap
			const renderer = createRenderer(nodeOps)
			const app = renderer.createApp(...args) // vue call
			const { mount } = app

			app.mount = doc => {
				const proxy = mount(doc)
				doc.nodeMap = nodeMap
				return proxy
			}
			return app
		}
		const app = createApp(App)
		for (const item of componentArr) {
			app.component(item.name, item)
		}
		const doc = newDocument()
		app.mount(doc) // this creates doc.nodeMap
		doc.nodeMap.shift() // The shift() method removes the first item of an array, we don't need first root
		if (doc.nodeMap.length > 0) {
			delete doc.nodeMap[0].parent
			// console.log('\nnodeMap raw', doc.nodeMap)

			/* const nodeMap = doc.nodeMap.map(item => {
				const ret = {}
				for (const key in item) {
					if (!key.startsWith('_') && key !== 'nodeMap') {
						ret[key] = item[key]
					}
				}
				if (item.__vnode && item.__vnode.props) {
					const item2 = item.__vnode.props
					ret.props = {}
					for (const key2 in item2) {
						if (item2[key2] != null && typeof item2[key2] !== 'function') {
							ret.props[key2] = item2[key2]
						}
					}
				}
				return ret
			}) */
		}
		runStartTime = perf.now() - runStartTime
		// console.log('\nnodeMap', doc.nodeMap)
		if (doc.nodeMap.length > 0) {
			let data = JSON.stringify(doc.nodeMap, null, 2)
			fs.writeFileSync('./page.json', data)
			console.log('* wrote file: ./page.json')
		}
		// renderToPDF(doc.doc.nodeMap)
		startTime = perf.now() - startTime

		const msg =
			`%c••• components create time: ` +
			(componentCreationTime / 1000).toFixed(4) +
			` seconds\n web page json create time: ` +
			(runStartTime / 1000).toFixed(4) +
			` seconds\n total time: ` +
			(startTime / 1000).toFixed(4) +
			` seconds •••\n`
		/* if (doc.nodeMap.length > 0) {
		} */
		console.warn('- please copy components from component-manually-fixed')
		console.log(msg, 'font-weight: bold; font-style: italic;')
		exec('cd ~/nc/nc-plugin/plugin/vue-renderer && npx prettier -w component2/**', (err, output) => {
			if (err) {
				console.error('could not execute command: ', err)
				return
			}
			console.log('npx prettier -w component2/** output:\n', output)
		})
	})
}
