// form/manager/erp-sync/page.js
/* global nc, dt */

return {
	name: 'ErpSync',
	data: {
		selectedRowRecord: null,
		selectedRecord: { local: null, external: null },
		tabIndex: { local: 0 }, // , external: 0
		tabPrevLoadTime: 0,
		tabRefreshSeconds: 1.0,
		sort: {}
	},
	computed: {
		tabLocal() {
			return this.arr && this.arr.tab && this.arr.tab.local
			/* 	const ret = this.arr.tab.local.filter(rec => {
					return rec.connection === this.rec.connection || !rec.connection
				})
				console.debug("tabLocal: ", ret)
				return ret */
		}
	},
	created() {
		console.debug('nc-erp-sync created')
		this.loadRows('local', 0, 'created') // first call will be init, it will load both areas at the same call
	},
	methods: {
		tabChanged(idx) {
			// tabChanged(idx, event, tab)
			if (idx === this.tabIndex.local) {
				let newTime = new Date()
				if (dt.secondsBetween(this.tabPrevLoadTime, newTime) < this.tabRefreshSeconds) {
					return
				}
			}
			if (idx != null) this.tabIndex.local = idx
			// this.tabIndex.external = this.tabIndex.local // external tab is not shown, keep tabs in sync
			this.$set(this.selectedRecord, 'local', null)
			this.$set(this.selectedRecord, 'external', null)
			nc.setGrid(this, 'local', Object.assign({}, this.grid.local))
			nc.setGrid(this, 'external', Object.assign({}, this.grid.external))
			this.grid.local.data = []
			this.grid.external.data = [] // clear data from screen
			this.loadRows('local') // better to have 2 calls, local answer will be faster
			this.loadRows('external')
			const table = this.tabValue('local')
			nc.gotoUrl(this, {
				name: 'erp-sync',
				query: { table: table, connection: this.rec.connection } // + '?connection=' + this.rec.connection
			})
			this.tabPrevLoadTime = new Date()
		},
		showRows(value) {
			nc.gridUpdateFilter(this, 'local')
			nc.gridUpdateFilter(this, 'external')
		},
		tabValue(area) {
			area = 'local' // always use local, external tab does not exist
			let idx = this.tabIndex[area]
			if (idx == null) return
			return (
				(this.arr && this.arr.tab && this.arr.tab[area] && this.arr.tab[area][idx] && this.arr.tab[area][idx].value) ||
				''
			)
		},
		rowTablePrefix(table) {
			return this.rec.table_prefix[table] + 'r'
		},
		gridSortChanged(area, sortArr) {
			this.sort[this.tabValue(area)] = sortArr
		},
		gridRowClicked(area, rowIndex, selected, event) {
			// this.$set and this.selectedRecord[area] must be used in buttonEnabled() to trigger calls to buttonEnabled()
			const arr = this.selectedRecordArr(area)
			// debugger
			this.$set(this.selectedRecord, area, null) // this.selectedRecord[area] = null // force change, if new value is same value as previous then this.$set() does nothing and it does not trigger buttonEnabled() call
			if (event) {
				nc.gridDeselectRows(this, this.otherArea(area))
				nc.gridSelectRowAndScrollToView(this, this.otherArea(area), event.data.link_rec_idx)
			}
			// 0 is not a truthy value, that's why we use rowIndex + 1
			if (selected) {
				// this.selectedRecord will be set on this.loadRecordRows() callback
				this.loadRecordRows(area, arr[0])
			} else {
				// was deselected
			}
		},
		loadRecordRows(area, rec) {
			console.debug('loadRecordRows', area, rec)
			const grid = this.grid[area]
			const table = this.tabValue(area)
			const tablePrefix = this.rec.table_prefix[table]
			if (area === 'local' && grid && (table === 'order-sales' || table === 'order-purchase')) {
				const rowTablePrefix = this.rowTablePrefix(table)
				const recordType = this.rec.record_type[table]
				// const rec = grid.data[rowIndex]
				const param = {
					"name": `form/manager/erp-sync/${this.rec.connection}/query-manager/order_row-${recordType}.json`,
					"parameter": {
						// "tag": tablePrefix,
						// "flat_table": rowTablePrefix,
						"record_id": rec[tablePrefix].record_id,
						"columns": `form/manager/erp-sync/${this.rec.connection}/columns/order_row-${recordType}.json`
					}
				}
				nc.callServer(this, "query/data", param, ret => {
					if (ret.data) {
						rec[tablePrefix][rowTablePrefix] = ret.data
						console.debug(`loadRecordRows callback rec, result: `, rec, ret)
					}
					this.$set(this.selectedRecord, area, rec)
					this.selectedRowRecord = rec && rec[tablePrefix]
				})
			} else {
				this.$set(this.selectedRecord, area, rec)
				this.selectedRowRecord = rec && rec[tablePrefix]
			}
		},
		loadRows(area, rowIndex, event) {
			let table = this.tabValue(area)
			const call = {
				// return: { grid: [{ name: 'external', tab: table }] }, // get initial return from rec.json
				// parameter: { table: table } // get initial from rec.json
			}
			let queryTab
			const callback = data => {
				if (data) {
					this.changeConnection()
					this.setGridData(area, data.grid || this.grid)
					if (data.grid) {
						table = this.tabValue(area)
						if (this.grid && this.grid.sort) {
							if (this.sort[table]) {
								this.grid.sort = this.sort[table]
							} else {
								this.sort[table] = this.grid.sort
							}
						}
						if (rowIndex != null) {
							this.gridRowClicked(this.otherArea(area), rowIndex, true)
						}
					}
				}
			}
			queryTab = (area, table) => {
				call.name = 'form/manager/erp-sync/' + this.rec.connection + '/grid.json'
				call.return = {
					grid: [
						{
							name: area,
							tab: table
						}
					]
				}
				nc.callServer(this, 'query', call, callback)
			}
			if (event !== 'created' && table !== '') {
				queryTab(area, table)
			} else {
				// first call, set tab index on callback
				call.name = 'form/manager/erp-sync/init.json'
				const connection = nc.searchParameter('connection')
				table = nc.searchParameter('table')
				if (connection || table) {
					call.parameter = {}
					if (connection) { // todo: check connection validity
						call.parameter.connection = connection
						this.rec.connection = connection
					}
					if (table) {
						call.parameter.table = table // todo: check table validity
					}
				}
				nc.setGrid(this, 'local', null)
				nc.setGrid(this, 'external', null)
				call.grid = 'form/manager/erp-sync/' + this.rec.connection + '/grid.json'
				nc.callServer(this, 'query', call, ret => {
					if (ret && ret.rec && ret.rec.tab) {
						setTimeout(() => { // we need setTimeout for tab to change, this.$nextTick is not enough
							// eslint-disable-next-line no-unused-vars
							for (const area in ret.rec.tab) {
								// wrong eslint error: error  'area' is defined but never used  no-unused-vars
								if (area === 'local') { // only local tab is in use
									const idx = nc.recordArrayIndex(this.arr.tab[area], 'value', ret.rec.tab[area])
									if (idx != null && idx !== this.tabIndex[area]) {
										// we need $nextTick here so that index is set after tab is drawn
										console.debug('+++++ this.tabIndex', idx, this.tabIndex[area])
										this.tabPrevLoadTime = new Date() // prevent double-load
										this.$set(this.tabIndex, area, idx)
									}
									this.loadRows('external') // local load is much faster, better to draw it first
								}
								callback(ret)
							}
						}, 0)
					}
				})
			}
		},
		selectedRecordArr(area) {
			const grid = this.grid && this.grid[area]
			if (!(grid && grid.grid && grid.grid.api)) {
				return []
			}
			let sel = grid.grid.api.getSelectedRows()
			return sel
		},
		buttonEnabled(button) {
			/* if (this.tabValue('local') !== this.tabValue('external')) {
				return false
			} */
			if (button === 'export') {
				let area = 'local'
				let table = this.tabValue(area)
				// debugger
				if (this.selectedRecord[area] && (table === 'product' || table === 'customer' || (table === 'order-sales' && this.rec.connection !== 'woocommerce') || table === 'order-purchase')) {
					const arr = this.selectedRecordArr(area)
					if (arr.length < 1)
						return
					if (table === 'order-sales' || table === 'order-purchase') {
						const prefix = this.rec.table_prefix[table]
						const rowPrefix = this.rowTablePrefix(table)
						return arr[0][prefix][rowPrefix] != null
					}
					return true
				}
				return false
			} else if (button === 'import') {
				let area = 'external'
				let table = this.tabValue(area)
				if (this.selectedRecord[area] && (table === 'product' || table === 'order-sales')) {
					const arr = this.selectedRecordArr(area)
					if (arr.length > 0) {
						// } && this.rec.allow_existing_product_import === true) {
						if (arr.length > 1 && table === 'order-sales') {
							return false
						}
						if (table === 'product') {
							return arr.every(rec => {
								return rec.pr.product_id && (rec.change_status === 'new' || rec.change_status === 'changed')
							})
						}
						return arr.every(rec => {
							return rec.change_status === 'new'
						})
					}
				}
				return false
			} else if (button === 'delete') {
				let area = 'external'
				let table = this.tabValue(area)
				if (this.selectedRecord[area] && (table === 'product' || table === 'customer')) {
					const arr = this.selectedRecordArr(area)
					if (arr.length < 1) return false
					if (table === 'product' && arr[0].pr.product_id === '') {
						return false
					}
					return true
				}
				return false
			}
			return false
		},
		isExternalFilterPresent() {
			if (this.rec.show_new !== true || this.rec.show_changed !== true || this.rec.show_equal !== true) {
				return true
			}
			return false
		},
		doesExternalFilterPass(node) {
			switch (node.data.change_status) {
				case 'new':
					return !(this.rec.show_new === false)
				case 'equal':
					return !(this.rec.show_equal === false)
				case 'changed':
					return !(this.rec.show_changed === false)
				default:
					return true
			}
		},
		setGridData(area, grid) {
			let table = this.tabValue(area)
			// const grid = this.grid
			let localData = grid && grid.local && grid.local.data
			let externalData = grid && grid.external && grid.external.data
			let otherIdx = -1
			let tablePrefix = this.rec.table_prefix[table]
			let compareField = this.rec.compare_field[table]
			if (localData && localData.length > 0) {
				// init local calculated data
				for (let i = 0; i < localData.length; i++) {
					let rec = localData[i]
					rec.link_rec_idx = -1
					rec.link_rec = null
					rec.change_status = 'new'
				}
			}
			if (externalData && externalData.length > 0) {
				// init external calculated data and set status on both data
				const doNotCompareFields = grid.external.columns
					.filter(rec => rec.change_compare === false)
					.reduce((acc, rec) => {
						acc[rec.field || rec.variable] = true
						return acc
					}, {})
				doNotCompareFields.link_rec_idx = true
				doNotCompareFields.link_rec = true
				doNotCompareFields.change_status = true

				const compareRecord = (rec, i) => {
					if (table === 'order-sales' || table === 'order-purchase') {
						if (localData && localData.length > 0 && localData[0][tablePrefix] && externalData[0]) {
							otherIdx = localData.findIndex(rec2 => {
								if (!rec2[tablePrefix] || rec2[tablePrefix][compareField] == null) {
									if (rec[tablePrefix][compareField] != null) {
										// no warning if both are null
										debugger
										nc.setWarning(
											this,
											`tablePrefix '${tablePrefix}' compareField '${compareField}' data is null`
										)
									}
									return false
								} else if (!rec[tablePrefix] || rec[tablePrefix][compareField] == null) {
									debugger
									nc.setWarning(this, `compareField '${compareField}' data is null`)
									return false
								}
								return (
									// 1 and "1" must be true here. so do not use ===, use ==
									// eslint-disable-next-line eqeqeq
									// rec[tablePrefix][compareField].toString().toLowerCase() == rec2[tablePrefix][compareField].toString().toLowerCase()
									rec[tablePrefix][compareField].toString().toLowerCase().trimEnd() == rec2[tablePrefix][compareField].toString().toLowerCase().trimEnd()
								)
							})
						}
					} else {
						if (
							localData &&
							localData.length > 0 &&
							localData[0][tablePrefix] &&
							externalData[0][tablePrefix]
						) {
							otherIdx = localData.findIndex(rec2 => {
								return (
									// 1 and "1" must be true here. so not ===, use ==
									// eslint-disable-next-line eqeqeq
									rec[tablePrefix][compareField].toString().toLowerCase() ==
									rec2[tablePrefix][compareField].toString().toLowerCase()
								)
							})
						}
					}
					if (otherIdx >= 0) {
						rec.link_rec_idx = otherIdx
						rec.link_rec = localData[otherIdx]
						if (table === 'order-sales' || table === 'order-purchase') {
							rec.ord.order_id = rec.link_rec.ord.order_id
							rec.ord.record_id = rec.link_rec.ord.record_id
						} else if (table === 'product') {
							rec.pr.record_id = rec.link_rec.pr.record_id
						}
						rec.change_status = nc.isEqualLoose(rec, localData[otherIdx], doNotCompareFields, this.rec.warning_sign)
							? 'equal'
							: 'changed'
						localData[otherIdx].link_rec_idx = i
						localData[otherIdx].link_rec = rec // link_rec will be circular reference
						localData[otherIdx].change_status = rec.change_status
					} else {
						console.debug(`  local record was not found for rec[tablePrefix][compareField]: '${rec[tablePrefix][compareField]}'`)
						rec.link_rec = null
						rec.link_rec_idx = -1
						rec.change_status = 'new'
						if (table === 'order-sales' || table === 'order-purchase') {
							rec.ord.order_id = ''
							rec.ord.record_id = ''
						} else if (table === 'product' && rec.pr) {
							rec.pr.record_id = ''
						}
					}
				}
				/* if (changedRec) {
					compareRecord(changedRec, -1)
				} else { */
				for (let i = 0; i < externalData.length; i++) {
					compareRecord(externalData[i], i)
				}
				// }
				// update grids
				nc.setGrid(this, 'local', Object.assign({}, this.grid.local))
				nc.setGrid(this, 'external', Object.assign({}, this.grid.external))
			}
		},
		changeConnection(updateData) {
			// nc.setArr(this, 'tab', this.arr.tab)
			if (updateData) {
				this.tabChanged()
			}
			if (this.rec && this.rec.logo_path_external_template)
				nc.setRec(
					this,
					'logo_path_external',
					this.rec.logo_path_external_template.replace('_connection_', this.rec.connection)
				)
		},
		otherArea(area) {
			return area === 'local' ? 'external' : 'local'
		},
		saveRows(area, action) {
			let table = this.tabValue(area)
			const arrOrig = this.selectedRecordArr(area)
			const prefix = this.rec.table_prefix[table]
			if (!prefix) {
				alert(`save table '${table}' is not valid`)
				return
			}
			const columns = this.grid[area].columns
			if (!columns || columns.length < 1) {
				alert(`save table '${table}' columns do not exist`)
				return
			}
			const arr = arrOrig.reduce((acc, rec, idx) => {
				delete rec.link_rec // we MUST delete this object or next functions and toJson will fail with infinite loop
				/* delete rec.id
				delete rec.link_rec_idx
				delete rec.change_status */
				let rec2 = nc.removeNonObjectKeys(rec)
				// copy those keys that do not have 'export: false' on column field definition
				rec2 = nc.copyRecByArrKeyValue(rec2, '', columns, 'field', (arrRec) => {
					return !arrRec || arrRec[action] !== false
				})
				acc[idx] = rec2
				return acc
			}, [])
			let param = {}
			if (action === 'import') {
				param.preference_name = 'form/manager/erp-sync/save/' + table + '.json'
			} else if (action === 'export') {
				param.preference_name = 'form/manager/erp-sync/' + this.rec.connection + '/save/' + table + '.json'
			}
			let callb = ret => {
				this.loadRows(this.otherArea(area))
				if (ret.result) {
					alert(ret.result)
				}
			}
			if (action === 'import') {
				param.save_data = arr
			} else if (action === 'export') {
				param.save_data = arr
			} else if (action === 'delete') {
				let doDelete
				if (table === 'product') {
					doDelete = confirm(`Are you sure you want to delete ${table} id ${arr[0].pr.product_id} ?`)
				} else if (table === 'company') {
					doDelete = confirm(`Are you sure you want to delete ${table} id ${arr[0].co.company_id} ?`)
				}
				if (doDelete === false) return
				param.delete_data = arr.map(rec => {
					return rec[prefix].json_data.transfer_id
				})
			} else {
				nc.setWarning(this, 'action is not export or delete')
				return
			}
			nc.saveJson(this, param, callb)
		}
	}
}
