// form/nc/nc-production/nc-production.js
const incrementalUpdate = nc.change.incrementalUpdate

// eslint-disable-next-line no-unused-vars
const chartRef = ref(null)
const chartOption = ref({})
const chartInitOption = ref({})
const ganttData = ref({})

let findText = ''
let areaName = 'product_need'
let findProductIdx = {}
let hasNeedWeekProductIdx = {}
let hasNeedProductIdx = {}
let productIdx = {}
let chartProductIdxArr = {}
let workEstimatedRecordIdx = {}
let needToIdxArr = {}
let needToWeekIdxArr = {}
let needFromWeekIdxArr = {}
let upperIdxArr = {}
let lowerIdxArr = {}
let selectedItemArr = []
let activatedRowIdxArr = []

let currentData, currentArea, stockChart, chartPref
let prevChartSelected = []
const chartData = []
let gridData, gridDataWeekly
let gridDataProductIdxArr, gridDataProductIdx, gridDataWeeklyProductIdx, gridDataWeeklyProductIdxArr

let updateFunc
const parseBefore = peg.parseBefore

onMounted(() => {
	incrementalUpdate(state)
	updateFunc = nc.debounce(updateFilter, (rec.find_delay_seconds && rec.find_delay_seconds * 1000) || 1000, false)
	if (!state.grid?.nats_name) {
		update('update') // first data load
	}
})

onUnmounted(() => {
	if (updateFunc) {
		updateFunc.cancel()
		updateFunc = null
	}
})

// eslint-disable-next-line no-unused-vars
function clickButton(action) {
	if (action === 'clear_find') {
		rec.find_text = ''
		prevCheckBoxValue = -1
		checkBoxClicked()
	} else if (action === 'add_order') {
		if (!rec.allow_save && rec.weekly_need) {
			return
		}
		selectedItemArr = nc.grid.activatedRecordArr(state, 'product_need_weekly')
		if (selectedItemArr.length > 0) {
			clearTimeout(addOrderErrorTimeout)
			clearCellError()
			const saveData = []
			const companyData = {}
			let hasError = false
			for (let item of selectedItemArr) {
				if (item.order_amount > 0 && item.company_id) {
					if (!companyData[item.company_id]) {
						companyData[item.company_id] = {
							company_id: item.company_id,
							ordr: []
						}
						saveData.push(companyData[item.company_id])
					}
					companyData[item.company_id].ordr.push({ product_id: item.product_id, order_amount: item.order_amount })
				} else {
					hasError = true
					item.show_cell_error = true
				}
			}
			if (hasError) {
				const { amountErrorCount, companyErrorCount } = updateAllowSave(null, true)
				const errorParts = []
				if (amountErrorCount > 0) {
					errorParts.push(`There are ${amountErrorCount} rows missing order amount`)
				}
				if (companyErrorCount > 0) {
					errorParts.push(`There are ${companyErrorCount} rows missing supplier company`)
				}
				const errorMessage =
					errorParts.length > 0
						? `${errorParts.join(' and ')}. Please fix before adding a new purchase order`
						: 'Please set order amount and supplier company id to all selected rows before adding a new purchase order'
				message.setInfo(state, nc.l(errorMessage), { callback: clearCellError })
				nc.grid.refreshCells(state, 'product_need_weekly')
				clearTimeout(addOrderErrorTimeout)
				addOrderErrorTimeout = setTimeout(clearCellError, rec.clear_error_timeout_seconds * 1000)
				return
			}
			if (saveData.length > 0) {
				nc.callServer(
					state,
					'save',
					{
						save: [{ table: 'order-purchase', save_preference: 'form/nc/nc-production/save-purchase-order.json', data: saveData }]
					},
					ret => {
						const saveArr = ret?.save && ret.save[0].data
						const orderNumArr = saveArr && saveArr.map(item => item.order_id)
						setTimeout(() => {
							if (orderNumArr && orderNumArr.length == 1) {
								message.setInfo(state, nc.l(`Saved purchase order '${orderNumArr[0]}'`))
							} else if (orderNumArr && orderNumArr.length > 1) {
								message.setInfo(state, nc.l(`Saved ${orderNumArr.length} purchase orders: ${orderNumArr.join(', ')}`))
							} else {
								message.setInfo(state, nc.l(`Purchase order save failed with error: ${ret.error}`))
							}
						}, 0)
					}
				)
			}
		}
	}
}

// work gantt chart
// let prevChartType = rec.chart_type
function showWorkPhase(checkTab) {
	let phaseArr
	const item = currentData && selectedItemArr[0]
	let showWork
	if (item && item.phase_part) {
		phaseArr = item.phase_part
		showWork = phaseArr && phaseArr.length > 0
	} else if (item && item.from_row) {
		showWork = true
		if (showWork) {
			const parent = currentData[item.from_row - 1]
			showWork = parent && parent.phase_part
			if (showWork) {
				phaseArr = parent.phase_part // parent.phase_part[item.record_id]
				showWork = phaseArr && phaseArr.length > 0
			}
		}
	}
	if (!showWork || (checkTab && rec.chart_type !== 'work_phase')) {
		ganttData.value = {}
		/* 	if (rec.chart_type === 'work_phase') {
			rec.chart_type = prevChartType
		} */
		return
	}
	if (rec.chart_type !== 'work_phase') {
		return
		/* TODO: restore when gantt works
		prevChartType = rec.chart_type
		rec.chart_type = 'work_phase' */
	}
	const workArr = []
	if (!item.production_order_id) {
		item.production_order_id = item.order_id
	}
	rec.selected_production_lot = item.production_order_id
	let phase, work
	let totalHours = 0
	let totalExtraHours = 0
	let totalSetupHours = 0
	for (let idx = 1; idx <= phaseArr.length; idx++) {
		phase = phaseArr[idx - 1]
		if (phase) {
			work = workEstimatedRecordIdx[phase.record_id]
			work.calc = { phase_part: phase.part, work_hours: phase.work_hours }
			work.start_dt = phase.start_dt
			work.end_dt = phase.end_dt
			work.end2_dt = phase.end2_dt
			work.setup_hours = phase.setup_hours
			work.extra_hours = phase.extra_hours
			work.production_order_id = item.production_order_id
			work.work_phase_state = item.from_depth ? parseBefore(item.from_depth, ' ') : 'production'
			work.remaining_amount = phase.amount // Math.round(phase.amount) // Math.round(parent.need_down)
			work.produced_amount = 0
			totalHours += phase.work_hours
			totalSetupHours += phase.setup_hours
			totalExtraHours += phase.extra_hours
			delete work._time_in_ms // force time calculations
			workArr.push(work)
			if (idx == phaseArr.length) {
				work = nc.clone(work)
				work.calc = {}
				work.start_dt = phase.part[phase.part.length - 1].end_dt
				work.end_dt = work.start_dt
				work.end2_dt = work.start_dt
				work.work_hours = totalHours
				work.setup_hours = totalSetupHours
				work.extra_hours = totalExtraHours
				work.work_phase_state = 'delivery'
				workArr.push(work)
			}
		}
	}
	updateGanttData(workArr)
}

function updateGanttData(workArr) {
	if (state?.grid?.gridIdx?.resourceIdx) {
		const capacityIdx = state.grid.gridIdx.capacityIdx
		const resourceIdx = state.grid.gridIdx.resourceIdx
		const usedResource = {}
		const resource = [] // create new array, do not change original data
		const capacityIdx2 = {} // create new array, do not change original data
		workArr.forEach(item => {
			if (!usedResource[item.resource_id]) {
				usedResource[item.resource_id] = true
				const res = resourceIdx[item.resource_id]
				const capArr = capacityIdx[item.resource_id]
				capacityIdx2[item.resource_id] = capArr
				resource.push({ start_dt: item.start_dt, resource_id: item.resource_id, show: res ? res.resource_name : resource, capArr: capArr })
			}
		})
		ganttData.value = { work_phase: workArr, resource: resource, capacityIdx: capacityIdx2 }
	}
}

let gridRowClickedTimeout
let addOrderErrorTimeout

function clearCellError() {
	clearTimeout(addOrderErrorTimeout)
	if (gridDataWeekly) {
		for (let idx = 1; idx <= gridDataWeekly.length; idx++) {
			if (gridDataWeekly[idx - 1].show_cell_error) {
				delete gridDataWeekly[idx - 1].show_cell_error
			}
		}
	}
	nc.grid.refreshCells(state, 'product_need_weekly')
}

// eslint-disable-next-line no-unused-vars
function gridRowClicked(areaName, rowIndex, event, selected) {
	clearTimeout(gridRowClickedTimeout)
	const itemArr = nc.grid.activatedRecordArr(state, areaName)
	if (itemArr.length === 0) {
		if (areaName === 'product_need_weekly') {
			clearHighlights(gridDataWeekly)
			nc.grid.refreshCells(state, areaName)
		} else {
			clearHighlights(currentData)
			nc.grid.refreshCells(state, areaName)
		}
	}
	gridRowClickedTimeout = setTimeout(() => {
		if (itemArr.length > 0) {
			selectGridRow(areaName, itemArr)
		}
	}, 100)
	if (gridDataWeekly && rec.weekly_need) {
		updateAllowSave(itemArr)
	}
}

function updateAllowSave(arr, countProblems) {
	if (rec.weekly_need) {
		const activated = arr || nc.grid.activatedRecordArr(state, 'product_need_weekly')
		rec.allow_save = activated && activated.length > 0
		rec.add_order_error = false
		let amountErrorCount = 0
		let companyErrorCount = 0
		if (activated) {
			for (let item of activated) {
				if (item.order_amount <= 0 || !item.company_id) {
					rec.add_order_error = true
					if (!countProblems) {
						return
					}
					if (item.order_amount <= 0) {
						amountErrorCount++
					}
					if (!item.company_id) {
						companyErrorCount++
					}
				}
			}
		}
		return { amountErrorCount, companyErrorCount }
	}
}

// eslint-disable-next-line no-unused-vars
function gridSelectionChanged(areaName) {
	clearTimeout(gridRowClickedTimeout)
	updateAllowSave()
	const itemArr = nc.grid.activatedRecordArr(state, areaName)
	if (itemArr.length === 0) {
		if (areaName === 'product_need_weekly') {
			clearHighlights(gridDataWeekly)
			nc.grid.refreshCells(state, areaName)
		} else {
			clearHighlights(currentData)
			nc.grid.refreshCells(state, areaName)
		}
	} else {
		selectGridRow(areaName, itemArr)
	}
}

// eslint-disable-next-line no-unused-vars
function gridRowDoubleClicked(area, rowIndex, event) {
	/* let arr = state.grid?.[area]?.data
	if (arr.length > rowIndex) {
		if (activatedRowIdxArr && activatedRowIdxArr.length > 0) {
			rowIndex = activatedRowIdxArr[0] - 1
		}
		rec.find_text = arr[rowIndex].product_id
		prevCheckBoxValue = -1
		setTimeout(checkBoxClicked, 100)
	} */
}

function selectGridRow(areaName, itemArr, scrollType) {
	selectedItemArr = itemArr
	if (currentData) {
		activatedRowIdxArr.length = 0
		clearHighlights(currentData)
		selectedItemArr.forEach(item => {
			if (!item?.idx) {
				console.debug(`🚀 ~ selectGridRow ~ item is null?:`, item)
				return
			} else {
				activatedRowIdxArr.push(item.idx)
				item.highlight = 'selected'
			}
		})
		showWorkPhase()
		activatedRowIdxArr = highlightUpperLower(selectedItemArr, activatedRowIdxArr)
		updateAllowSave()
		if (scrollType !== 'scroll-first') {
			scrollType = 'no-scroll'
		}
		if (scrollType !== 'no-scroll' && activatedRowIdxArr.length > 0) {
			nc.grid.scrollToRow(state, areaName, activatedRowIdxArr[0], scrollType)
		}
		updateChartProduct(activatedRowIdxArr)
		if (areaName === 'product_need_weekly') {
			nc.grid.redrawRows(state, areaName)
		} else {
			nc.grid.refreshCells(state, areaName)
		}
	}
}

function clearHighlights(data) {
	if (!data) {
		return
	}
	for (let idx = 1; idx <= data.length; idx++) {
		const item = data[idx - 1]
		if (item.highlight === 'selected' || item.highlight === 'upper' || item.highlight === 'lower') {
			delete item.highlight
		}
	}
}

function updateChart() {
	chartOption.value = null // trigger nc-chart option watch
	if (rec.chart_type === 'work_phase') {
		showWorkPhase()
	} else {
		setTimeout(() => {
			chartOption.value = chartPref[rec.chart_type]
		}, 0)
	}
}

// nc-svg-map
let mapSelected = ref([])

// eslint-disable-next-line no-unused-vars
let mapHover = ref([])

// eslint-disable-next-line no-unused-vars
function mapToggleSelected(param) {
	console.debug('map click', param.id, param.event)
	const i = mapSelected.value.indexOf(param.id)
	if (i === -1) mapSelected.value.push(param.id)
	else mapSelected.value.splice(i, 1)
}

// eslint-disable-next-line no-unused-vars
function mapDoubleClick(param) {
	console.debug('map double click', param.id, param.event)
}

// nc-gantt needs function mousemove
// eslint-disable-next-line no-unused-vars
function mousemove(id, e) {
	mouse.value.mousemove = `${id}: ${Math.floor(e.offsetX)}x${Math.floor(e.offsetY)}`
}
const mouse = ref({
	mouseover: null,
	mouseout: null,
	mousemove: null,
	click: null,
	drag: null,
	dragend: null
})

// nc-chart stock balance
let defaultDataset, defaultSeries
function updateChartProduct(selectedArray) {
	let chartMin = 0
	let chartMax = 0
	let item, pr
	stockChart.dataset.length = 2
	stockChart.series.length = 1
	let chartId = 0
	if (!defaultDataset) {
		defaultDataset = nc.clone(stockChart.dataset[0])
		defaultSeries = nc.clone(stockChart.series[0])
	}
	const chartSelected = []
	if (selectedArray.length === 0) {
		stockChart.dataset[chartId] = null
		stockChart.series[chartId] = null
	}
	const count = rec.chart_current ? 1 : selectedArray.length < chartPref.max_product_count ? selectedArray.length : chartPref.max_product_count
	for (let i = 0; i < count; i++) {
		item = currentData[selectedArray[i] - 1]
		pr = productIdx[item.product_id]
		if ((pr && pr.hasBalance) || i === 0) {
			chartSelected.push(item.product_id)
			if (pr) {
				if (pr.minBalance < chartMin) {
					chartMin = pr.minBalance
				}
				if (pr.maxBalance > chartMax) {
					chartMax = pr.maxBalance
				}
			}
			if (stockChart.dataset[chartId] == null) {
				stockChart.dataset[chartId] = nc.clone(defaultDataset)
			}
			stockChart.dataset[chartId].source = chartProductIdxArr[item.product_id] || []
			if (stockChart.series[chartId] == null) {
				stockChart.series[chartId] = nc.clone(defaultSeries)
			}
			stockChart.series[chartId].name = chartPref.show_product_name ? item.name || productIdx[item.product_id]?.name || item.product_id : item.product_id
			stockChart.series[chartId].datasetIndex = chartId
			chartId++
		}
	}
	if (chartSelected.length === prevChartSelected.length && nc.isEqual(chartSelected, prevChartSelected)) {
		return
	}
	prevChartSelected = chartSelected
	chartMin = Math.floor(chartMin)
	if (chartMin < 0) {
		chartMin = chartMin - 1
	}
	chartMax = Math.floor(chartMax) + 1
	stockChart.yAxis[0].min = chartMin
	stockChart.yAxis[1].min = chartMin
	stockChart.yAxis[0].max = chartMax
	stockChart.yAxis[1].max = chartMax
	updateChart()
}

function calculateScopeForData(data, isWeekly) {
	if (data.length < 1) {
		return
	}
	if (data[1].scope != null) {
		return
	}
	for (let i = 1; i <= data.length; i++) {
		upperIdxArr[i] = []
		lowerIdxArr[i] = []
	}
	for (let i = 1; i <= data.length; i++) {
		const item = data[i - 1]
		let parentIdx
		if (isWeekly) {
			const fromArr = needFromWeekIdxArr[i]
			if (fromArr && fromArr.length > 0) {
				parentIdx = fromArr[0]
			}
		} else {
			parentIdx = item.from_row
		}
		if (parentIdx) {
			lowerIdxArr[parentIdx].push(i)
			upperIdxArr[i].push(parentIdx)
		}
	}
	for (let i = 1; i <= data.length; i++) {
		let count = 0
		let current = i
		while (true) {
			const parentArray = upperIdxArr[current]
			if (!parentArray || parentArray.length === 0) break
			count++
			current = parentArray[0]
		}
		const item = data[i - 1]
		const scope = []
		if (count > 0) {
			scope.push(`↑${count}`)
		}
		if (lowerIdxArr[i].length > 0) {
			scope.push(`↓${lowerIdxArr[i].length}`)
		}
		item.scope = scope.join(' ')
	}
}

function updateData(ret) {
	if (!state.grid) {
		message.setError(state, "state grid is not defined, can't update data")
		return
	}
	let chartStartDate, chartEndDate
	chartProductIdxArr = {}
	workEstimatedRecordIdx = nc.createIndex(state.grid['product_work-estimated'].data, 'record_id').index
	let data = ret?.data?.chart_option
	if (data) {
		chartPref = data
		stockChart = chartPref.stock_balance // chartPref[rec.chart_type]
		chartStartDate = new Date()
		chartStartDate.setHours(0, 0, 0, 0)
		chartStartDate = chartStartDate.getTime()
		chartEndDate = new Date()
		chartEndDate.setHours(0, 0, 0, 0)
		chartEndDate.setDate(chartEndDate.getDate() + chartPref.chart_days || 60)
		chartEndDate = chartEndDate.getTime()
		stockChart.xAxis.min = chartStartDate
		stockChart.xAxis.max = chartEndDate
		chartStartDate = chartStartDate / 1000
		chartEndDate = chartEndDate / 1000
		chartInitOption.value = chartPref.init_option
		chartOption.value = stockChart
		chartData.length = 0
	}
	let pr, item
	const grid = ret.grid
	data = grid?.product?.data
	if (data) {
		productIdx = nc.createIndex(data, 'product_id')
		if (productIdx.warning) {
			message.setWarning(state, `duplicate id's when creating product id index: ${JSON.stringify(productIdx.warning)}`)
		}
		productIdx = productIdx.index
	}
	hasNeedWeekProductIdx = {}
	hasNeedProductIdx = {}
	needToIdxArr = {}
	needToWeekIdxArr = {}
	rec.error_count_all = 0
	rec.error_count_week = 0
	gridData = grid?.product_need?.data
	if (gridData) {
		data = gridData
		let prevItem, item2
		for (let idx = 1; idx <= data.length; idx++) {
			item = data[idx - 1]
			if (item.first_row) {
				pr = productIdx[item.product_id]
				pr.minBalance = 0
				pr.maxBalance = 0
				if (item.last_row && item.balance === 0) {
					item.is_empty = true
				}
				if (pr.error && pr.error !== item.error) {
					if (item.error) {
						item.error += '\n' + pr.error
					} else {
						item.error = pr.error
					}
				}
			}
			if (item.error) {
				rec.error_count_all++
			}
			item.pr = pr
			if (pr && item.balance && item.balance !== 0) {
				pr.hasBalance = true
				if (item.balance < pr.minBalance) {
					pr.minBalance = item.balance
				}
				if (item.balance > pr.maxBalance) {
					pr.maxBalance = item.balance
				}
			}
			if (!hasNeedProductIdx[item.product_id] && (item.balance < 0 || (item.need_down && item.need_down > 0))) {
				hasNeedProductIdx[item.product_id] = true
			}
			if (item.from_row) {
				if (!needToIdxArr[item.from_row]) {
					needToIdxArr[item.from_row] = [item.idx]
				} else {
					needToIdxArr[item.from_row].push(item.idx)
				}
			}
			if (item.date && item.date >= 0) {
				if (item.date < chartStartDate) {
					item.before_today = true
				}
				if (stockChart) {
					/* if (item.product_id === 'SSH 1,5*1250*2500 ELECTROGALV.') {
						item.date = item.date + 0
					} */
					if (item.first_row) {
						item.balance_date = chartStartDate * 1000
					} else if (item.date > chartStartDate && item.date < chartEndDate) {
						item.balance_date = item.date * 1000 // to js milliseconds day
					} else if (item.date >= chartEndDate) {
						item.balance_date = chartEndDate * 1000 // show future events then end of the chart
					} else {
						item.balance_date = chartStartDate * 1000 // first row balance date is always today = chart start date
					}
					if (item.first_row && item.last_row) {
						item.balance_date = chartStartDate * 1000
						chartData.push(item)
						item2 = { product_id: item.product_id, name: item.name || item.pr?.name, balance_date: chartEndDate * 1000, balance: item.balance }
						chartData.push(item2)
					} else if (!item.first_row) {
						if (prevItem.first_row && item.balance_date >= prevItem.balance_date && item.product_id === prevItem.product_id) {
							prevItem.balance_date = chartStartDate * 1000
							item2 = { product_id: item.product_id, name: prevItem.name || prevItem.pr?.name, balance_date: chartStartDate * 1000, balance: prevItem.balance }
							chartData.push(item2)
						}
						if (item.balance_date > prevItem.balance_date && prevItem.balance !== item.balance && item.product_id === prevItem.product_id) {
							// balance chart lines must not be in angles but straight up or down, previous item balance continues until next item changes it
							item2 = { product_id: prevItem.product_id, name: prevItem.name || prevItem.pr?.name, balance_date: item.balance_date, balance: prevItem.balance }
							chartData.push(item2)
							chartData.push(item)
						} else {
							chartData.push(item)
						}
						if (item.last_row && prevItem.balance_date < chartEndDate * 1000 && item.balance !== prevItem.balance) {
							// continue last balance to end of the graph
							item2 = { product_id: item.product_id, name: item.name || item.pr?.name, balance_date: chartEndDate * 1000, balance: item.balance }
							chartData.push(item2)
						}
					}
					prevItem = item
				}
			}
		}
		gridData.forEach(item => {
			pr = productIdx[item.product_id]
			if (needToIdxArr[item.idx] && pr && (pr.needToIdxArr == null || pr.needToIdxArr.length < needToIdxArr[item.idx].length)) {
				pr.needToIdxArr = needToIdxArr[item.idx]
			}
			if (item.from_row && pr && pr.needFromIdx == null) {
				pr.needFromIdx = item.from_row
			}
		})
		chartProductIdxArr = nc.createIndexArray(chartData, 'product_id')
		if (stockChart) {
			currentData = gridData
			updateChartProduct([])
		}
	}
	state.grid.gridIdx['company-supplier-company_id'] = nc.createIndex(state.grid['company-supplier'].data, 'company_id').index
	const companyIdx = state.grid.gridIdx['company-supplier-company_id']
	gridDataWeekly = grid?.product_need_weekly?.data
	if (gridDataWeekly) {
		data = gridDataWeekly
		for (let idx = 1; idx <= data.length; idx++) {
			item = data[idx - 1]
			item.idx = idx
			item.calc = gridData[item.calc_idx - 1]
			item.calc.week_idx = idx
			item.product_id = item.calc.product_id
			item['co-supplier'] = companyIdx[item.company_id] // TODO: move index creation and this to nc-grid-common.js
			pr = productIdx[item.product_id]
			item.pr = pr
			if (pr.error && pr.error !== item.error) {
				if (item.error) {
					item.error += '\n' + pr.error
				} else {
					item.error = pr.error
				}
			}
			if (item.error) {
				rec.error_count_week++
			}
			if (!hasNeedWeekProductIdx[item.product_id] && (item.amount > 0 || (pr && (pr.going_amount < 0 || pr.free_amount < 0)))) {
				hasNeedWeekProductIdx[item.product_id] = true
			}
			if (item.calc.first_row && item.calc.last_row && item.balance === 0) {
				if (pr && pr.json_data.coming_amount === 0 && pr.json_data.going_amount === 0 && pr.json_data.free_amount === 0) {
					item.is_empty = true
				}
			}
			if (item.date && item.date >= 0 && item.date < chartStartDate) {
				item.before_today = true
			}
		}
	}
	gridDataProductIdxArr = nc.createIndexArray(gridData, 'product_id')
	gridDataProductIdx = nc.createIndex(gridData, 'product_id', null, 'no-warning').index
	gridDataWeeklyProductIdx = nc.createIndex(gridDataWeekly, 'product_id', null, 'no-warning').index
	gridDataWeeklyProductIdxArr = nc.createIndexArray(gridDataWeekly, 'product_id')
	if (gridDataWeekly) {
		let item, rec, arrCalc
		for (let idx = 1; idx <= gridDataWeekly.length; idx++) {
			item = gridDataWeekly[idx - 1]
			pr = productIdx[item.product_id]
			arrCalc = pr && pr.needToIdxArr
			if (arrCalc) {
				const newArr = []
				const newArrIdx = {}
				arrCalc.forEach(rowIdx => {
					rec = gridData[rowIdx - 1]
					if (!newArrIdx[rec.product_id] && gridDataWeeklyProductIdx[rec.product_id]) {
						newArrIdx[rec.product_id] = true
						newArr.push(gridDataWeeklyProductIdx[rec.product_id].idx)
					}
				})
				needToWeekIdxArr[idx] = newArr
			}
			if (pr && pr.needFromIdx) {
				const newArr = []
				rec = gridData[pr.needFromIdx - 1]
				if (gridDataWeeklyProductIdx[rec.product_id]) {
					newArr.push(gridDataWeeklyProductIdx[rec.product_id].idx)
				}
				needFromWeekIdxArr[idx] = newArr
			}
		}
	}
	rec.error_count = rec.weekly_need ? rec.error_count_week : rec.error_count_all
	// Update currentArea and currentData to match the current view
	needViewChanged()
}

function findAllUpper(upperProductIdx) {
	if (rec.select_upper !== true) {
		return
	}
	let foundUpper = false
	let arr, item2
	const alreadyFound = {}
	const sourceData = rec.weekly_need ? gridData : currentData
	const dataProductIdx = rec.weekly_need ? gridDataWeeklyProductIdxArr : gridDataProductIdxArr
	do {
		foundUpper = false
		for (const productId in upperProductIdx) {
			if (!alreadyFound[productId]) {
				alreadyFound[productId] = true
				arr = dataProductIdx[productId]
				if (!arr) {
					continue
				}
				arr.forEach(item => {
					const fromRow = rec.weekly_need ? item.calc && item.calc.from_row : item.from_row
					if (fromRow) {
						item2 = sourceData[fromRow - 1]
						if (item2 && !upperProductIdx[item2.product_id]) {
							foundUpper = true
							upperProductIdx[item2.product_id] = true
						}
					}
				})
			}
		}
	} while (foundUpper === true)
}

function setTreeChart(treeArr) {
	if (treeArr.length > 1) {
		let longestChildrenItem // find treeArr item with most children and use only it
		treeArr.forEach(item => {
			if (!longestChildrenItem) {
				longestChildrenItem = item
				if (!longestChildrenItem.children) {
					longestChildrenItem.children = []
				}
			} else if (item.children && item.children.length > longestChildrenItem.children.length) {
				longestChildrenItem = item
			}
		})
		treeArr = [longestChildrenItem]
	}
	chartPref.product_tree.series.length = 1
	chartPref.product_tree.series[0].left = '15%'
	// chartPref.product_tree.series[0].right = '15%'
	chartPref.product_tree.series[0].data = treeArr
	updateChart()
}

function highlightUpperLower(selectedItems, arr) {
	const itemHighlight = {}
	if (rec.select_upper === true) {
		selectedItems.forEach(item => {
			let current = item.idx
			while (true) {
				const parentArray = upperIdxArr[current]
				if (!parentArray || parentArray.length === 0) break
				const parentIdx = parentArray[0]
				itemHighlight[parentIdx] = 'upper'
				if (arr.indexOf(parentIdx) === -1) {
					arr.push(parentIdx)
				}
				current = parentIdx
			}
		})
	}
	if (rec.select_lower === true) {
		const treeArr = []
		selectedItems.forEach(item => {
			const descendants = lowerIdxArr[item.idx] || []
			descendants.forEach(descendantIdx => {
				const row = currentData[descendantIdx - 1]
				if (row.highlight !== 'upper' && row.highlight !== 'selected') {
					itemHighlight[descendantIdx] = 'lower'
					if (arr.indexOf(descendantIdx) === -1) {
						arr.push(descendantIdx)
					}
				}
			})
			const tree = { children: [] }
			buildTreeChart(item.idx, tree)
			if (tree.children[0]) {
				treeArr.push(tree.children[0])
			}
		})
		setTreeChart(treeArr)
	}
	for (const idx in itemHighlight) {
		currentData[idx - 1].highlight = itemHighlight[idx]
	}
	return arr
}

function buildTreeChart(parentIdx, parentNode) {
	const row = currentData[parentIdx - 1]
	if (!row) {
		return
	}
	const node = {
		name: row.pr.name + ' (' + row.product_id + ')',
		value: nc.round(row.balance, 2),
		parent: row.product_id,
		children: []
	}
	parentNode.children.push(node)
	const children = rec.weekly_need === true ? needToWeekIdxArr[parentIdx] || [] : needToIdxArr[parentIdx] || []
	children.forEach(childIdx => {
		buildTreeChart(childIdx, node)
	})
}

// eslint-disable-next-line no-unused-vars
function doesExternalFilterPass(node) {
	return itemFound(node.data)
}

let findTextArr
function createFindTextArr(text) {
	findTextArr = text
		.toLowerCase()
		.split(' ')
		.map(text => text.trim())
		.filter(text => text.length > 0)
}

function itemFound(item) {
	let allow = true
	if (rec.has_error && !item.error) {
		allow = false
	}
	if (allow && rec.only_need) {
		if (rec.weekly_need) {
			allow = hasNeedWeekProductIdx[item.product_id]
		} else {
			allow = hasNeedProductIdx[item.product_id]
		}
	}
	if (allow && rec.hide_empty && item.is_empty) {
		allow = false
	}
	if (allow && findProductIdx[item.product_id]) {
		return true
	}
	if (allow && findText) {
		if (!findTextArr) {
			createFindTextArr(findText)
		}
		for (let text of findTextArr) {
			allow =
				item.product_id.toLowerCase().includes(text) ||
				(item.name && item.name.toLowerCase().includes(text)) ||
				(item.calc?.name && item.calc.name.toLowerCase().includes(text)) ||
				(item.production_order_id && item.production_order_id.toLowerCase().includes(text)) ||
				(item.order_id && item.order_id.toLowerCase().includes(text)) ||
				(item.company_id && item.company_id.toLowerCase().includes(text)) ||
				false
			if (allow) {
				return true
			}
		}
	}
	return allow === true
}

let prevFindText = ''
let prevCheckBoxValue = 0
function updateFilter(findText_, checkBoxValue) {
	// console.time('* find products')
	findText = findText_.toLowerCase()
	if (prevFindText !== findText) {
		createFindTextArr(findText)
	}
	let found = false
	const doFind = currentData && findText.length >= rec.find_min_characters
	const activatedRowIdxArr = []
	findProductIdx = {}
	if (doFind) {
		let item
		for (let idx = 1; idx <= currentData.length; idx++) {
			item = currentData[idx - 1]
			const sourceItem = rec.weekly_need ? item.calc : item
			if (itemFound(sourceItem)) {
				findProductIdx[item.product_id] = true
				if (activatedRowIdxArr.length <= rec.max_activate_row_count + 1) {
					activatedRowIdxArr.push(idx)
				}
				const sourceLevel = sourceItem.level
				if (sourceLevel && sourceLevel > 1) {
					found = true
				} else if (found === false) {
					found = 0
				}
			}
		}
	}
	if (found === true) {
		findAllUpper(findProductIdx)
	}
	nc.grid.updateFilter(state, currentArea)
	prevFindText = findText
	prevCheckBoxValue = checkBoxValue
}

function needViewChanged() {
	// const prevWeeklyNeed = rec.weekly_need
	rec.weekly_need = rec.need_view == 'balance' ? true : false
	if (rec.weekly_need) {
		currentArea = 'product_need_weekly'
		currentData = gridDataWeekly
	} else {
		currentArea = 'product_need'
		currentData = gridData
		// Switching to Need tab - load detailed grid with incremental update if enabled
		/* if (prevWeeklyNeed && rec.incremental_update) {
			nc.callServer(
				state,
				'calc/product-need',
				{
					parameter: {
						incremental_update: rec.incremental_update
					}
				},
				ret => {
					const wasIncremental = incrementalUpdate(state, ret)
					if (!wasIncremental && (ret.grid?.product_need || ret.grid?.product_need_weekly)) {
						updateData(ret)
					}
					updateFilter(prevFindText, prevCheckBoxValue)
				}
			)
		} */
	}
	calculateScopeForData(currentData, rec.weekly_need)
}

let prevWeeklyNeed = rec.weekly_need
function checkBoxClicked() {
	needViewChanged()
	const checkBoxValue = rec.hide_empty + rec.only_need * 10 + rec.has_error * 100 + rec.weekly_need * 1000
	if (rec.weekly_need) {
		rec.error_count = rec.error_count_week
	} else {
		rec.error_count = rec.error_count_all
	}
	if (prevWeeklyNeed !== rec.weekly_need) {
		prevWeeklyNeed = rec.weekly_need
		updateFilter(rec.find_text, checkBoxValue) // update immediately
		/* if (rec.weekly_need === true) {
			return
		} */
		if (selectedItemArr[0]) {
			const productIdArr = selectedItemArr.map(item => item.product_id)
			let idx
			if (rec.weekly_need) {
				idx = gridDataWeeklyProductIdx
			} else {
				idx = gridDataProductIdx
			}
			selectedItemArr.length = productIdArr.length
			for (let index = 0; index < productIdArr.length; index++) {
				selectedItemArr[index] = idx[productIdArr[index]]
			}
			selectGridRow(areaName, selectedItemArr, 'scroll-first') // we are selecting only product's first balance row, they never cause lower or upper level selection
		}
	} else if (checkBoxValue !== prevCheckBoxValue) {
		updateFilter(rec.find_text, checkBoxValue) // do not wait for debounce, update immediately
	} else if (rec.find_text !== prevFindText) {
		updateFunc(rec.find_text, checkBoxValue)
	}
}

// eslint-disable-next-line no-unused-vars
function updateLower() {
	if (rec.weekly_need) {
		areaName = 'product_need_weekly'
	} else {
		areaName = 'product_need'
	}
	selectedItemArr = nc.grid.activatedRecordArr(state, areaName)
	if (selectedItemArr.length > 0) {
		if (rec.select_lower == false) {
			selectedItemArr.length = 1
		}
		selectGridRow(areaName, selectedItemArr)
	}
}

function update(action, reload) {
	if (action === 'update') {
		if (rec.view === 'product-need') {
			const prevReload = state.rec.reload_data
			if (reload) {
				state.rec.reload_data = true
			}
			nc.callServer(
				state,
				'calc/product-need',
				{
					parameter: {
						reload_data: rec.reload_data,
						create_schedule: rec.create_schedule,
						virtual_production_order: rec.virtual_production_order,
						estimate_order: rec.estimate_order,
						old_work_date: rec.old_work_date,
						max_need_down_loop_count: rec.max_need_down_loop_count,
						minimum_stock: rec.minimum_stock,
						action_limit: rec.action_limit,
						negative_start_balance: rec.negative_start_balance,
						negative_end_balance: rec.negative_end_balance,
						critical_date: rec.critical_date,
						only_sales_need: rec.only_sales_need,
						incremental_update: rec.incremental_update
					}
				},
				ret => {
					if (reload) {
						state.rec.reload_data = prevReload
					}
					const wasIncremental = incrementalUpdate(state, ret)
					if (!wasIncremental && (ret.grid?.product_need || ret.grid?.product_need_weekly)) {
						updateData(ret)
					}
					updateFilter(prevFindText, prevCheckBoxValue)
				}
			)
		}
	}
}
