// ../core/nc-state.js
// ../../core/nc-state.js

import { reactive } from 'vue'
import { recDataSet } from './nc-util.js'
let message = {} // import message from '../../core/nc-message.js'
let getSyncState // import { getSyncState } from './nc-sync-state.js'
let getMainSate // import { getMainSate } from '../../core/nc-main.js'
let mainStateObj

export function mainState() {
	if (!mainStateObj) {
		mainStateObj = getMainSate()
	}
	return mainStateObj
}

export function isState(obj) {
	return obj && obj.message && typeof obj.commit === 'function'
}

export function newState(owner, obj) {
	obj = obj || {}
	const state = reactive({
		commit: commit,
		owner: owner,
		message: {},
		// error: null, // null keeps key reactive, we must define all used keys here - null works
		rec: obj.rec || {}, // html rec.xxx causes errors in first draw without default object
		hdr: obj.hdr || {}, // prevent html hdr.xxx warnings with default object
		// prev_rec: null,
		arr: obj.arr,
		grid: obj.grid,
		data: obj.data,
		css: obj.css
	})
	if (obj.warning) {
		message.setWarning(state, obj.warning)
	}
	if (obj.error) {
		message.setError(state, obj.error)
	}
	for (let key in obj) {
		if (state[key] == null && key !== 'error' && key !== 'warning' && key !== 'base_path') {
			message.setInfo(state, `new state object has extra key '${key}', value '${obj[key]}'`)
		}
	}
	state.getSyncState = getSyncState
	return state
}

function commit(vm, key, data) {
	if (vm == null) {
		debugger
		console.error('setValue vm or key is null')
		return
	}
	let state = vm.state || vm
	// if (data.option) {
	const oldValue = key === 'state' ? state[data.key] : state[key] && state[key][data.key]
	if (this.owner !== state.owner) {
		// if (this !== state) {
		console.error(`* commit state owner '${this.owner} / ${state.owner}', is not same: ${this !== state}`)
	}
	let keyName = key
	if (data.key != null) {
		keyName = keyName + '.' + data.key
	}
	if (key === 'prev_rec') {
		data.value = state.rec[data.key] // data.value is needed to set for console.debug
	}
	if (typeof oldValue === 'string' || typeof data.value === 'string') {
		// console.debug(`* commit state '${state.owner}', update '${keyName}', value changed from: '${oldValue}' ==> '${data.value}'`)
	} else {
		console.debug(
			`* commit state '${state.owner}', update '${keyName}', value changed from: `,
			oldValue,
			` ==> `,
			data.value
			// `, data.option: `, data.option
		)
	}
	if (
		!(
			(
				key === 'rec' ||
				key === 'prev_rec' ||
				key === 'hdr' ||
				key === 'arr' ||
				key === 'grid' ||
				key === 'data' ||
				key === 'message' ||
				key === 'error' ||
				key === 'state' ||
				key === 'merge_state'
			)
			// key === 'tbl'
		)
	) {
		debugger
		console.error(`* update state 'state', key '${data.key}' is not valid, value: `, data.value)
		return
	}
	if (key === 'rec') {
		mainStateObj = mainStateObj || mainState()
		if (mainStateObj && mainStateObj.inputValueChanged) {
			mainStateObj.inputValueChanged(data.key, data.value, data.event)
		}
		setValue(state, key, data.key, data.value)
	} else if (key === 'arr') {
		setValue(state, key, data.key, data.value)
		// state[key].value[data.key] = data.value
	} else if (key === 'hdr') {
		setValue(state, key, data.key, data.value)
	} else if (key === 'prev_rec') {
		/* if (!state.orig_rec) {
			state.orig_rec = clone(state.rec)
		} */
		if (!state.prev_rec) {
			state.prev_rec = {}
		}
		state.prev_rec[data.key] = data.value // prev_rec does not need to be reactive
		// setValue(state, key, data.key, data.value)
	} else if (key === 'state') {
		recDataSet(state, data.key, data.value) // state[data.key] = data.value // recDataSet will keep new key reactive
	} else if (key === 'merge_state') {
		if (state[data.key] === undefined) {
			recDataSet(state, data.key, data.value) // main key does not exist, no need to loop subkeys
		} else if (Object.keys(state[data.key]).length === 0) {
			// nc.isEmpty(state[data.key])
			recDataSet(state, data.key, data.value) // main key is empty object, no need to loop subkeys
		} else {
			for (let newKey in data.value) {
				if (Object.prototype.hasOwnProperty.call(data.value, newKey)) {
					setValue(state, data.key, newKey, data.value[newKey])
				}
			}
		}
	} else if (key === 'grid') {
		setValue(state, key, data.key, data.value)
	} else if (key === 'data') {
		if (data.key !== 'data') {
			console.error(`* update state, data.key is not 'data'`)
			return
		}
		recDataSet(state, data.key, data.value) // state[data.key] = data.value
	} else if (key === 'message') {
		recDataSet(state, key, data.value) // state[key] = data.value // data.key is undefined
	} else if (key === 'error') {
		debugger
		recDataSet(state, key, data.value) // state[key] = data.value // test this, data.key is undefined
	} else {
		console.error(`  - update state, unsupported key '${key}'`)
		debugger
	}
}

function setValue(state, stateKey, key, value) {
	let stateRec = state[stateKey]
	if (stateRec === undefined) {
		console.debug(`  - state key '${stateKey}' is undefined, new value: '{}'`)
		recDataSet(state, stateKey, {})
		stateRec = state[stateKey]
	}
	if (value === undefined) {
		console.debug(`  - state key '${stateKey}.${key}', old value '${stateRec[key]}', new value is undefined: '`, value, `'`)
	}
	if (stateRec[key] === undefined) {
		let logValue = value
		if (typeof value === 'string' && value.length > 500) {
			logValue = value.substring(0, 500) + '...'
		}
		console.debug(`  - state key '${stateKey}.${key}' is undefined, new value: '`, logValue, `'`)
		// null is valid value in rec.json, do not warn about it
	}
	recDataSet(stateRec, key, value) // recDataSet will keep new key reactive
}
