/**
 * @type {string}
 */
var trainNumber
/**
 * @type {Date}
 */
var date
var groupIndex = null

var yesterday = false
var showKm = false

var trainData = null
/**
 * @type {?Date}
 */
var lastSuccessfulFetch = null

/**
 * @typedef ArrDep
 * @property {string} scheduleTime
 * @property {?{delay: number, real: boolean}} status
 *
 * @typedef Note
 * @property {string} kind
 *
 * @typedef DepartsAsNote
 * @type {Note}
 * @property {"departsAs"} kind
 * @property {string} rank
 * @property {string} number
 *
 * @typedef TrainNumberChangeNote
 * @type {Note}
 * @property {"trainNumberChange"} kind
 * @property {string} rank
 * @property {string} number
 *
 * @typedef DetachingWagonsNote
 * @type {Note}
 * @property {"detachingWagons"} kind
 * @property {string} station
 *
 * @typedef ReceivingWagonsNote
 * @type {Note}
 * @property {"receivingWagons"} kind
 * @property {string} station
 *
 * @typedef TrainStop
 * @property {string} name
 * @property {number} km
 * @property {?number} stoppingTime
 * @property {?string} platform
 * @property {ArrDep} arrival
 * @property {ArrDep} departure
 * @property {Note[]} notes
 *
 * @typedef Group
 * @property {{from: string; to: string}} route
 * @property {{delay: number; station: string; state: "passing" | "arrival" | "departure"} | undefined} status
 * @property {TrainStop[]} stations
 */

/**
 * @param {{ rank: string; number: string; operator: string; date: string; groups: Group[]; }} data
 * @param {?Date} fetchDate
 */
function onTrainData(data, fetchDate) {
	var title = document.getElementById('title')
	title.textContent = ''
	title.appendChild(document.createTextNode('Train '))
	var rankSpan = document.createElement('span')
	rankSpan.textContent = data.rank
	rankSpan.classList.add(data.rank)
	title.appendChild(rankSpan)
	title.appendChild(document.createTextNode(` ${data.number}`))

	document.getElementsByTagName('title')[0].textContent = `Train ${data.rank} ${data.number}`

	document.getElementById('company').textContent = data.operator
	var dateHref = document.createElement('a')
	var dateP = document.getElementById('date')
	while (dateP.childNodes.length > 0) {
		dateP.childNodes[0].remove()
	}
	dateP.appendChild(dateHref)
	dateHref.textContent = data.date
	dateHref.href = '#'
	dateHref.classList.add('no-a-custom')
	dateHref.classList.add('items', 'no-a-custom')
	dateHref.addEventListener('click', function (e) {
		e.preventDefault()
		// Implement date switcher
		yesterday = !yesterday
		refresh()
	})

	document.getElementById('loading').classList.add('hidden')

	/**
	 * @type {Group | null}
	 */
	var group = null;
	if (data.groups.length > 1 && groupIndex == null) {
		document.getElementById('group-choice').classList.remove('hidden')
		document.getElementById('group-choice').focus()
		document.getElementById('train-info').classList.add('hidden')

		document.getElementsByClassName('rsk')[0].textContent = ''
		document.getElementsByClassName('csk')[0].textContent = 'Select'

		title.textContent = `Select Group for ${data.rank} ${data.number}`

		var gc = document.getElementById('group-choice')
		while (gc.childNodes.length > 0) {
			gc.childNodes[0].remove()
		}

		for (var i = 0; i < data.groups.length; i++) {
			var g = data.groups[i]

			var groupLi = document.createElement('li')
			gc.append(groupLi)
			groupLi.tabIndex = i
			groupLi.classList.add('items')
			if (i === currentIndex) {
				groupLi.focus()
			}

			(function (i) {
				function onAction(e) {
					var url = new URL(window.location.toString())
					groupIndex = i
					url.searchParams.append('groupIndex', groupIndex)
					window.history.pushState({'groupIndex': groupIndex}, '', url.toString( ))
					onTrainData(data)
				}
				groupLi.addEventListener('click', onAction)
				groupLi.addEventListener('keypress', function (e) {
					if (e.key == 'Enter') {
						onAction(e)
					}
				})
			})(i)

			var routeP = document.createElement('p')
			groupLi.append(routeP)
			routeP.classList.add('pri')
			routeP.textContent = `${g.route.from} ➔ ${g.route.to}`

			var groupP = document.createElement('p')
			groupLi.append(groupP)
			groupP.classList.add('thi')
			groupP.textContent = i === 0 ? 'Main train' : `Group ${i}`

		}

		return
	}
	else if (data.groups.length === 1) {
		group = data.groups[0]
	}
	else {
		group = data.groups[groupIndex]
	}
	document.getElementById('group-choice').classList.add('hidden')
	document.getElementById('train-info').classList.remove('hidden')
	document.getElementById('train-info').focus()

	document.getElementsByClassName('rsk')[0].textContent = 'Refresh'
	document.getElementsByClassName('csk')[0].textContent = ''

	document.getElementById('route-from').textContent = group.route.from
	document.getElementById('route-to').textContent = group.route.to

	if (group.status) {
		document.getElementById('status').classList.remove('hidden')

		var statusDelay = document.getElementById('status-delay')
		while (statusDelay.childNodes.length > 0) {
			statusDelay.childNodes[0].remove()
		}
		var delayString = ''
		var delayMinutes = group.status.delay
		if (delayMinutes === 0) {
			delayString = 'On time'
			statusDelay.appendChild(document.createTextNode(delayString))
		}
		else {
			var early = false
			if (delayMinutes < 0) {
				early = true
				delayMinutes = -delayMinutes
			}
			
			if (delayMinutes >= 60) {
				var hours = Math.floor(delayMinutes / 60)
				delayMinutes = delayMinutes % 60
				delayString += hours.toString()
				delayString += ' hour'
				if (hours > 1) {
					delayString += 's'
				}
			}
			if (delayMinutes > 0) {
				if (delayString.length > 0) {
					delayString += ' and '
				}
				delayString += delayMinutes.toString()
				delayString += ' minute'
				if (delayMinutes > 1) {
					delayString += 's'
				}
			}
			delayString += ' '
			statusDelay.appendChild(document.createTextNode(delayString))

			var kindSpan = document.createElement('span')
			statusDelay.appendChild(kindSpan)
			if (early) {
				kindSpan.textContent = 'early'
				kindSpan.classList.add('early')
			}
			else {
				kindSpan.textContent = 'late'
				kindSpan.classList.add('late')
			}
		}

		var statusLocation = document.getElementById('status-location')
		while (statusLocation.childNodes.length > 0) {
			statusLocation.childNodes[0].remove()
		}
		var stateString = ''
		if (group.status.state === 'arrival') {
			stateString += 'when arriving at '
		}
		else if (group.status.state === 'departure') {
			stateString += 'when departing from '
		}
		else if (group.status.state === 'passing') {
			stateString += 'while passing through '
		}
		statusLocation.appendChild(document.createTextNode(stateString))
		var stationSpan = document.createElement('span')
		statusLocation.appendChild(stationSpan)
		stationSpan.textContent = group.status.station
		stationSpan.classList.add('station')
	}
	else {
		document.getElementById('status').classList.add('hidden')
	}

	var stationsDiv = document.getElementById('stations')
	while (stationsDiv.childNodes.length > 0) {
		stationsDiv.childNodes[0].remove()
	}

	var separator = document.createElement('h4')
	stationsDiv.appendChild(separator)
	separator.textContent = 'Stations'

	var stationsList = document.createElement('ul')
	stationsDiv.appendChild(stationsList)

	group.stations.forEach(function (station) {
		var stationItem = document.createElement('li')
		stationsList.appendChild(stationItem)
		stationItem.classList.add('stationItem')

		var stationName = document.createElement('p')
		stationItem.appendChild(stationName)
		stationName.classList.add('pri', 'name')
		var stationNameHref = document.createElement('a')
		stationName.appendChild(stationNameHref)
		stationNameHref.textContent = station.name
		stationNameHref.classList.add('items', 'no-a-custom')
		var stationUrl = new URL('/view-station.html', window.location.origin)
		stationUrl.searchParams.append('station', station.name)
		stationUrl.searchParams.append('date', (station.arrival || station.departure).scheduleTime)
		stationNameHref.href = stationUrl.toString()

		if (station.arrival) {
			var stationArrival = document.createElement('div')
			stationItem.appendChild(stationArrival)
			stationArrival.classList.add('arrival')

			var originalArr = document.createElement('p')
			stationArrival.appendChild(originalArr)
			var originalArrSpan = document.createElement('span')
			originalArr.appendChild(originalArrSpan)
			var arrDate = new Date(station.arrival.scheduleTime)
			originalArrSpan.textContent = arrDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
			originalArr.classList.add('pri')
			if (station.arrival.status && station.arrival.status.delay != 0) {
				originalArr.classList.remove('pri')
				originalArr.classList.add('thi')
				originalArrSpan.classList.add('original')
				var delaySpanArr = document.createElement('span')
				originalArr.appendChild(delaySpanArr)
				delaySpanArr.textContent = `${station.arrival.status.delay > 0 ? '+' : ''}${station.arrival.status.delay}`;
				delaySpanArr.classList.add(station.arrival.status.delay > 0 ? 'late' : 'early')
				delaySpanArr.style.marginLeft = '4px'

				var actualArr = document.createElement('p')
				stationArrival.appendChild(actualArr)
				arrDate.setMinutes(arrDate.getMinutes() + station.arrival.status.delay)
                actualArr.textContent = arrDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
				actualArr.classList.add('pri', station.arrival.status.delay > 0 ? 'late' : 'early')
				if (!station.arrival.status.real) {
					actualArr.classList.add('not-real')
				}
			}
		}

		if (station.departure) {
			var stationDeparture = document.createElement('div')
			stationItem.appendChild(stationDeparture)
			stationDeparture.classList.add('departure')

			var originalDep = document.createElement('p')
			stationDeparture.appendChild(originalDep)
			var depDate = new Date(station.departure.scheduleTime)
			var originalDepSpan = document.createElement('span')
			originalDep.appendChild(originalDepSpan)
			originalDepSpan.textContent = depDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
			originalDep.classList.add('pri')
			if (station.departure.status && station.departure.status.delay != 0) {
				originalDep.classList.remove('pri')
				originalDep.classList.add('thi')
				originalDepSpan.classList.add('original')
				var delaySpanDep = document.createElement('span')
				originalDep.appendChild(delaySpanDep)
				delaySpanDep.textContent = `${station.departure.status.delay > 0 ? '+' : ''}${station.departure.status.delay}`;
				delaySpanDep.classList.add(station.departure.status.delay > 0 ? 'late' : 'early')
				delaySpanDep.style.marginLeft = '4px'

				var actualDep = document.createElement('p')
				stationDeparture.appendChild(actualDep)
				depDate.setMinutes(depDate.getMinutes() + station.departure.status.delay)
                actualDep.textContent = depDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
				actualDep.classList.add('pri', station.departure.status.delay > 0 ? 'late' : 'early')
				if (!station.departure.status.real) {
					actualDep.classList.add('not-real')
				}
			}
		}

		var stationKm = document.createElement('p')
		stationItem.appendChild(stationKm)
		stationKm.textContent = `${station.km} km`
		stationKm.classList.add('thi', 'km')
		if (!showKm) {
			stationKm.classList.add('hidden')
		}

		if (station.platform) {
			var stationPlatform = document.createElement('p')
			stationItem.appendChild(stationPlatform)
			stationPlatform.textContent = `platform ${station.platform}`
			stationPlatform.classList.add('thi', 'platform')
		}

		if (station.notes && station.notes.length > 0) {
			var stationNotes = document.createElement('div')
			stationItem.appendChild(stationNotes)
			stationNotes.classList.add('notes')

			station.notes.forEach(function (note) {
				var noteP = document.createElement('p')
				stationNotes.appendChild(noteP)
				noteP.classList.add('note', 'thi')

				switch (note.kind) {
					case 'departsAs': {
						noteP.textContent = `Train departs as ${note.rank} ${note.number}`
						break
					}
					case 'detachingWagons': {
						noteP.textContent = `Detaching wagons to ${note.station}`
						break
					}
					case 'receivingWagons': {
						noteP.textContent = `Receiving wagons from ${note.station}`
						break
					}
					case 'trainNumberChange': {
						noteP.textContent = `Train changes number to ${note.rank} ${note.number}`
						break
					}
				}
			})
		}
	})

	lastSuccessfulFetch = fetchDate || new Date()
}

var refreshStopToken = null

/**
 * @returns {Promise<boolean>}
 */
function refresh() {
	function reschedule(timeout) {
		if (refreshStopToken != null) {
			clearTimeout(refreshStopToken)
		}
		refreshStopToken = setTimeout(function () { 
			refresh()
		}, timeout || 60000)
	}
	/**
	 * @type {Date}
	 */
	var reqDate = new Date(date.valueOf())
	if (yesterday) {
		reqDate.setDate(reqDate.getDate() - 1)
	}
	return fetch(
		`https://scraper.infotren.dcdev.ro/v3/trains/${trainNumber}?date=${reqDate.getFullYear().toString()}-${(reqDate.getMonth() + 1).toString().padStart(2, "0")}-${reqDate.getDate().toString().padStart(2, "0")}`,
		{
			cache: 'no-store',
		},
	).then(function (response) {
		if (!response.ok) {
			// Check in 10 seconds if server returned error
			reschedule(10000)
			return
		}
		var cacheDate = response.headers.get('SW-Cached-At')
		return response.json().then(function (data) {
			data['$cacheDate'] = cacheDate
			return data
		})
	}).then(function (response) {
		if (!response) {
			return
		}
		var cacheDate = response['$cacheDate']
		if (cacheDate) {
			cacheDate = new Date(cacheDate)
		}
		var success = !cacheDate
		trainData = response
		onTrainData(response, cacheDate)
		// Check in 1 seconds if network error
		reschedule(success ? undefined : 1000)
		return success
	}).catch(function (e) {
		// Check in 1 second if network error
		reschedule(1000)
		throw e
	})
}

window.addEventListener('unload', function (e) {
	if (refreshStopToken != null) {
		clearTimeout(refreshStopToken)
	}
})

function rsk() {
	function changeRskText(newText) {
		document.querySelectorAll('.rsk').forEach(function (elem) {
			elem.textContent = newText
		})
	}

	changeRskText('Refreshing...')
	refresh().catch(function () { return false}).then(function (success) {
		if (!success) {
			changeRskText('Refreshing failed')
			setTimeout(function (_) {
				changeRskText('Refresh')
			}, 3000)
		}
		else {
			changeRskText('Refresh')
		}
	})
}

window.addEventListener('popstate', function (e) {
	groupIndex = null
	if (trainData) {
		onTrainData(trainData)
	}
	else {
		refresh()
	}
})

window.addEventListener('load', function (e) {
	if (!new URL(window.location.href).searchParams.has('train')) {
		window.history.back()
		this.setTimeout(function () {
			var url = new URL(window.location.href)
			url.pathname = 'train.html'
			window.location.href = url.toString()
		}, 100)
	}

	var sp = new URL(window.location.href).searchParams

	trainNumber = sp.get('train')
	date = sp.has('date') ? new Date(sp.get('date')) : new Date()
	groupIndex = sp.has('groupIndex') ? parseInt(sp.get('groupIndex')) : null

	document.querySelectorAll('.rsk').forEach(function (rskElem) {
		rskElem.addEventListener('click', function (e) {
			rsk()
		})
	})

	var content = document.getElementsByClassName('content')[0]
	content.focus()
	content.addEventListener('keydown', function (e) {
		switch (e.key) {
			// case 'ArrowUp':
			// 	content.scrollBy(0, -50)
			// 	break
			// case 'ArrowDown':
			// 	content.scrollBy(0, 50)
			// 	break
			case 'SoftRight':
				rsk()
				break
			case '1':
				date.setDate(date.getDate() - 1)
				refresh()
				break
			case '3':
				date.setDate(date.getDate() + 1)
				refresh()
				break
			case '7':
				showKm = !showKm
				document.querySelectorAll('.km').forEach(function (kmItem) {
					if (showKm) {
						kmItem.classList.remove('hidden')
					}
					else {
						kmItem.classList.add('hidden')
					}
				})
				break
			default:
				console.log(e.key)
		}
	})

	refresh()

	setInterval(function () {
		if (!lastSuccessfulFetch) {
			return
		}
		var millis = new Date() - lastSuccessfulFetch
		var secs = Math.floor(millis / 1000)
		
		var timeStr = ''
		if (secs / 3600 >= 1) {
			timeStr += `${Math.floor(secs / 3600)}h`
			secs = secs % 3600
		}
		if (secs / 60 >= 1) {
			timeStr += `${Math.floor(secs / 60)}m`
			secs = secs % 60
		}
		if (secs >= 1) {
			timeStr += `${Math.floor(secs)}s`
		}
		if (!timeStr) {
			document.querySelectorAll('.lsk').forEach(function (elem) {
				elem.textContent = 'Last refreshed now'
				elem.classList.add('last-refreshed')
			})
		}
		else {
			document.querySelectorAll('.lsk').forEach(function (elem) {
				elem.textContent = `Last refreshed ${timeStr} ago`
				elem.classList.add('last-refreshed')
			})
		}
	}, 500)

	if (this.localStorage && !this.localStorage.getItem('info-yesterday')) {
		this.alert("New feature: You can now view yesterday's train by selecting the date!")
		this.localStorage.setItem('info-yesterday', 'true')
	}
})