// /src/core/nc-dt.js
import { isDate, isNil, isObject } from './nc-util.js'
// import { Temporal } from 'proposal-temporal'

/* // import localeFI from 'dayjs/esm/locale/fi'
import dayjs from 'dayjs/esm'
import utc from 'dayjs/esm/plugin/utc'
import isoWeek from 'dayjs/esm/plugin/isoWeek'
// import customParseFormat from 'dayjs/esm/plugin/customParseFormat'
// import isToday from 'dayjs/esm/plugin/isToday'
// import isBetween from 'dayjs/esm/plugin/isBetween'
// import localizedFormat from 'dayjs/esm/plugin/localizedFormat'
// import advancedFormat from 'dayjs/esm/plugin/advancedFormat'
// import isSameOrBefore from 'dayjs/esm/plugin/isSameOrBefore'
// import isSameOrAfter from 'dayjs/esm/plugin/isSameOrAfter'
// import weekOfYear from 'dayjs/esm/plugin/weekOfYear'
dayjs.extend(utc)
dayjs.extend(isoWeek) */

const dt = {}
export default dt

let defaultLocale
if (typeof window === 'undefined') {
	defaultLocale = 'en' // not in browser
} else {
	defaultLocale = window.navigator.userLanguage || window.navigator.language // use nc language
}
let currentLanguage = defaultLocale // undefined // info: old Edge does not support 'default' but it supports undefined
// let defaultFormat = 'YYYY-MM-DD HH:mm:ss' // 2020-01-30 23:12:21
// let defaultSaveFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ' // 2020-01-30T20:12:21.123Z
// let timeOffsetInMS = new Date().getTimezoneOffset() * 60000 // Intl.DateTimeFormat() changes time to lcal time, when does summertime start/end?, this changes

function browserDateFormat() {
	let now = new Date(2013, 11, 31)
	let str = now.toLocaleDateString()
	str = str.replace('31', 'DD')
	str = str.replace('12', 'MM')
	str = str.replace('2013', 'YYYY')
	return str
}
const defaultDateFormat = browserDateFormat()
const defaultTimeFormat = 'HH:mm:ss' // 23:12:21
/* let localeDateFormat = {
	month: '2-digit', // "01"
	day: '2-digit', // "01"
	year: 'numeric' // "2019"
} */
const localeDateFormat = new Intl.DateTimeFormat(currentLanguage, {
	month: '2-digit', // "01"
	day: '2-digit', // "01"
	year: 'numeric' // "2019"
})
/* const localeTimestampFormat = {
	month: '2-digit', // "01"
	day: '2-digit', // "01"
	year: 'numeric', // "2019",
	hour: 'numeric',
	minute: 'numeric',
	second: 'numeric'
	// timeZoneName: 'short'
} */
const localeTimestampFormat = new Intl.DateTimeFormat(currentLanguage, {
	dateStyle: 'short',
	timeStyle: 'medium'
})
/* let localeDatetimeFormat = new Intl.DateTimeFormat(currentLanguage, {
	dateStyle: 'medium',
	timeStyle: 'short'
}) */
let localeDatetimeFormat = new Intl.DateTimeFormat(currentLanguage, {
	month: '2-digit', // "01"
	day: '2-digit', // "01"
	year: 'numeric', // "2019",
	hour: '2-digit',
	minute: '2-digit'
})

const minDate = new Date(0) // "1970-01-01"
minDate.setDate(minDate.getDate() - 1)
const maxDate = new Date(0)
maxDate.setDate(maxDate.getDate() + 1)
dt.isZeroDate = function (date) {
	debugger
	if (isDate(date)) {
		return date >= minDate && date <= maxDate
	}
	if (typeof date === 'number') {
		return date === 0
	}
	return date.startsWith('1970-01-01') || date.startsWith('1969-12-31')
}

dt.timeFormat = function () {
	return defaultTimeFormat
}

dt.setLocale = function () {
	// function (locale)
	// todo: load locales from rest server
	/*
	let language = locale.toLowerCase()
	import(`/node_modules/dayjs/esm/locale/${language}.js`)
		.then(ret => {
			dayjs.locale(ret.default)
			console.debug(`* loaded dayjs locale '${language}'`)
		})
		.catch(() => {
			language = language.split('-')
			language = language[1] || language[0]
			import(`/node_modules/dayjs/esm/locale/${language}.js`)
				.then(ret => {
					dayjs.locale(ret.default)
					console.debug(`* loaded dayjs locale${language}`)
				})
				.catch(err => {
					console.error(`could not import dayjs locale '${language}'`)
				})
		}) */
}
dt.setLocale(defaultLocale)

dt.formatDate = function (date, format) {
	if (!isDate(date)) {
		date = dt.parseTime(date)
		if (!isDate(date)) {
			return ''
		}
	}
	if (format) {
		if (format === 'save') {
			debugger
			return date.toISOString().replace('.000Z', 'Z') // dayjs(date).utc().format()
		} else if (!isObject(format)) {
			// debugger // return dayjs(date).format(format)
			if (format === 'datetime') {
				// debugger
				return localeDatetimeFormat.format(date).replace('klo ', '') // todo: add replace as preference, 'klo ' is finnish 'at' time text
			}
			if (format !== defaultDateFormat) {
				// TODO: change format string to object or use object always in calls
				return localeDateFormat.format(date) // date.toLocaleDateString(currentLanguage, localeDateFormat)
			}
		}
	}
	if (date === '0000-00-00') {
		return ''
	} else if (!isDate(date)) {
		date = dt.parseDate(date)
		// date.setTime(date.getTime() - timeOffsetInMS)
	}
	if (format) {
		return date.toLocaleDateString(currentLanguage, format)
	}
	if (!isDate(date)) {
		console.error('date is not valid', date)
	} else {
		return localeDateFormat.format(date)
	}
	return date
}

dt.formatTimeStamp = function (date, format) {
	if (format) {
		if (format === 'save') {
			debugger
			return date.toISOString().replace('.000Z', 'Z') // dayjs(date).utc().format()
		} else if (!isObject(format)) {
			debugger // return dayjs(date).format(format)
			if (format !== defaultDateFormat) {
				// TODO: change format string to object or use object always in calls
				return localeTimestampFormat.format(date) // date.toLocaleDateString(currentLanguage, localeTimestampFormat)
			}
		}
	}
	if (date == 0 || date === '0000-00-00') {
		return ''
	} else if (typeof date === 'number') {
		date = new Date(date * 1000) // data is seconds, convert to milliseconds
	} else if (!isDate(date)) {
		date = dt.parseTime(date)
		// date.setTime(date.getTime() - timeOffsetInMS)
	}
	return localeTimestampFormat.format(date) // date.toLocaleDateString(currentLanguage, format || localeTimestampFormat)
}

dt.formatSeconds = function (milliseconds) {
	return dt.formatDate(new Date(milliseconds)) // dayjs(milliseconds).format(defaultTimeFormat) // dayjs format is better for localization
}

dt.secondDifference = function (start, end) {
	return (end - start) / 1000 // https://day.js.org/docs/en/display/difference
}

dt.secondsBetween = function (start, end) {
	return Math.abs(dt.secondDifference(end, start))
}

dt.isTextDate = function (fldVal) {
	if (typeof fldVal === 'string' && fldVal.length === 10 && fldVal.match(/(\d{4})-(\d{2})-(\d{2})/)) {
		return true
	}
	return false
}

dt.parseTime = function (dateString) {
	let date, day, hour, min, month, sec, year
	if (dateString == null) {
		return null
	}
	if (dateString === '0000-00-00 00:00:00') {
		return new Date(0) // "1970-01-01"
	} else if (typeof dateString === 'number') {
		return new Date(dateString * 1000)
	} else {
		if (dateString.match(/(\d{2})\.(\d{2})\.(\d{4})/)) {
			day = dateString.substr(0, 2)
			month = dateString.substr(3, 2)
			year = dateString.substr(6, 4)
		} else {
			year = dateString.substr(0, 4)
			month = dateString.substr(5, 2)
			day = dateString.substr(8, 2)
		}
		hour = dateString.substr(11, 2)
		if (hour === '') {
			date = new Date(year, month - 1, day)
			return date
		}
		min = dateString.substr(14, 2)
		sec = dateString.substr(17, 2)
		date = new Date(year, month - 1, day, hour, min, sec)
		// date.setMinutes(date.getMinutes() + dt.timezoneOffsetMinutes())
		return date
	}
}

dt.dateToString = function (date, format) {
	if (typeof date === 'string') {
		return date
	}
	if (!isDate(date)) {
		return '1970-01-01' // null date, there is no null time 00:00:00 is valid
	}
	if (format) {
		return dt.formatDate(date, format)
	}
	let year = date.getFullYear()
	let month = date.getMonth() + 1
	let day = date.getDate()
	if (month < 10) {
		month = '0' + month
	}
	if (day < 10) {
		day = '0' + day
	}
	return year + '-' + month + '-' + day
}

// not-core

dt.formatDateTime = function (date, format) {
	if (!isDate(date)) {
		date = dt.parseTime(date)
		if (!isDate(date)) {
			return ''
		}
	}
	let y = date.getFullYear()
	if (y === 1970 || y === 1901) {
		let m = date.getMonth()
		let d = date.getDate()
		if (m === 0 && d === 1) {
			// month 0-11
			return ''
		}
	}
	// debugger // change to dayjs format
	return dt.formatDate(date, format || 'dd.mm.yyyy HH:MM:ss') // ma.defaultDateFormat()) # "dd.mm.yyyy" yyyy-mm-dd
}

function addPrefixZero(number) {
	if (number < 10) {
		return '0' + number
	}
	return number
}

dt.formatSecondsToTime = function (seconds) {
	if (seconds === 0) {
		return ''
	}
	// const now = new Date()
	// const date = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, seconds)
	// const date = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, seconds)
	// return addPrefixZero(date.getUTCHours()) + ':' + addPrefixZero(date.getUTCMinutes()) + ':' + addPrefixZero(date.getUTCSeconds())
	// return addPrefixZero(date.getHours()) + ':' + addPrefixZero(date.getMinutes()) + ':' + addPrefixZero(date.getSeconds())
	const hours = Math.floor(seconds / 3600)
	seconds = seconds - hours * 3600
	const minutes = Math.floor(seconds / 60)
	seconds = seconds - minutes * 60
	return addPrefixZero(hours) + ':' + addPrefixZero(minutes) + ':' + addPrefixZero(seconds)
}

function currentDate() {
	return new Date()
}
dt.currentDate = currentDate

dt.currentDateUtc = function () {
	const now = new Date()
	return new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds())
}

dt.hourDifference = function (start, end) {
	return dt.secondDifference(start, end) / 3600
}

const oneDayInMs = 24 * 60 * 60 * 1000 // hours * minutes * seconds * milliseconds
dt.dayDifference = function (startTime, endTime) {
	// found in mg_scripts
	if (isDate(startTime)) {
		return Math.floor((endTime.getTime() - startTime.getTime()) / oneDayInMs) // return Math.ceil()
	}
	if (typeof startTime !== 'string') {
		return Math.floor(endTime) - Math.floor(startTime)
	}
	const date1 = dt.parseDate(startTime)
	const date2 = dt.parseDate(endTime)
	// return Math.floor(date2.getTime() - date1.getTime()) / oneDayInMs // returns decimal numbers
	return parseInt((date2.getTime() - date1.getTime()) / oneDayInMs)
}

dt.dayCount = function (start, end) {
	return dt.dayDifference(start, end) + 1
}

dt.weekDayCount = function (start, end) {
	let count, days, i
	days = dt.dayCount(start, end)
	start = start.getDay() // moment(start).weekday // Gets or sets the ISO day of the week with 1 being Monday and 7 being Sunday.
	count = 0
	i = 0
	while (i < days) {
		start++
		if (start > 7) {
			// sunday
			start = 1
		} else if (start >= 1 && start <= 5) {
			// monday - friday
			count++
		}
		i++
	}
	return count
}

// -- new code
dt.parseDate = function (dateString) {
	let d, day, month, year
	if (dateString === '0000-00-00' || dateString === 0) {
		return new Date(0) // "1970-01-01"
	} else if (typeof dateString === 'string') {
		year = dateString.substr(0, 4)
		month = dateString.substr(5, 2)
		day = dateString.substr(8, 2)
		if (!(year && month && day)) {
			console.warn(`dt.parseDate, invalid date text to parse: `, dateString)
			return new Date(0)
		}
		d = new Date(year, month - 1, day)
	} else {
		console.warn(`dt.parseDate, unknown date text to parse: `, dateString)
		return new Date(0)
	}
	return d
}

dt.toHourMin = function (d) {
	let hour, min
	if (!d || d === void 0) {
		return '00:00:00'
	}
	hour = d.getHours()
	if (hour < 10) {
		hour = '0' + hour
	}
	min = d.getMinutes()
	if (min < 10) {
		min = '0' + min
	}
	return hour + ':' + min
}

dt.timeToString = function (d) {
	let hour, min, sec
	if (!d || d === void 0) {
		return '00:00:00'
	}
	hour = d.getHours()
	if (hour < 10) {
		hour = '0' + hour
	}
	min = d.getMinutes()
	if (min < 10) {
		min = '0' + min
	}
	sec = d.getSeconds()
	if (sec < 10) {
		sec = '0' + sec
	}
	return dt.dateToString(d) + ' ' + hour + ':' + min + ':' + sec
}

dt.addDays = function (theDate, days) {
	// returns always yyyy-mm-dd (and possible hh:mm:ss) format
	if (isNil(theDate)) {
		return null
	}
	if (isDate(theDate)) {
		return new Date(theDate.getTime() + days * 24 * 60 * 60 * 1000)
	}
	if (theDate.length <= 10) {
		// this handles time changes
		// https://stackoverflow.com/questions/563406/add-days-to-javascript-date
		let ret = dt.parseDate(theDate)
		ret.setDate(ret.getDate() + days)
		return dt.dateToString(ret)
	}
	let ret = dt.parseTime(theDate)
	ret.setTime(ret.getTime() + days * 24 * 60 * 60 * 1000)
	return dt.timeToString(ret).substr(0, theDate.length)
}

dt.julianToDate = function (num) {
	// julianToYmd(julian)
	let a, b, c, d, date, day, e, int, m, month, year
	int = dt.floatToInt(num) // days are integer part of number
	a = int + 32044
	b = Math.floor((4 * a + 3) / 146097)
	c = a - Math.floor((146097 * b) / 4)
	d = Math.floor((4 * c + 3) / 1461)
	e = c - Math.floor((1461 * d) / 4)
	m = Math.floor((5 * e + 2) / 153)
	day = e - Math.floor((153 * m + 2) / 5) + 1
	month = m + 3 - 12 * Math.floor(m / 10)
	year = 100 * b + d - 4800 + Math.floor(m / 10)
	date = new Date(0) // new Date() would return current date
	date.setFullYear(year, month - 1, day) // JavaScript counts months from 0 to 11
	return date // not called
}

dt.dateToJulian = function (date) {
	let year = date.getFullYear() // http://www.w3schools.com/jsref/jsref_obj_date.asp
	let month = date.getMonth() + 1 // js month is 0-11
	let day = date.getDate()
	let a = Math.floor((14 - month) / 12)
	let y = year + 4800 - a
	let m = month + 12 * a - 3
	return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045
}

dt.julianToWeek = function (jd) {
	let d4 = (((jd + 31741 - (jd % 7)) % 146097) % 36524) % 1461
	let L = Math.floor(d4 / 1460)
	let d1 = ((d4 - L) % 365) + L
	return Math.floor(d1 / 7) + 1
}

dt.dateToWeek = function (date) {
	return dt.julianToWeek(dt.dateToJulian(date))
}

dt.unixToDate = function (unixTime) {
	let theDate
	theDate = new Date(unixTime * 1000)
	// offset = theDate.getTimezoneOffset() * 60
	// theDate.setSeconds(theDate.getSeconds() - offset)
	// dateString = theDate.toGMTString()
	return theDate // not called
}

/* dt.dateToUnix = (inYear, inMon, inDay, inHr, inMin, inSec ) ->
humDate = new Date(Date.UTC(inYear, inMon - 1, inDay, inHr, inMin, inSec))
result = (humDate.getTime() / 1000.0)
return result
*/

function dateToUnix(date) {
	return date.getTime() / 1000.0
}
dt.dateToUnix = dateToUnix

function dateToNum(date) {
	// found in mg_scripts
	let num = dt.dateToUnix(date)
	num -= date.getTimezoneOffset() * 60 // TODO: test with positive TimezoneOffset
	return num // not called
}
dt.dateToNum = dateToNum

dt.currentDateTime = function () {
	return dateToNum(currentDate()) // currentDate/currentDateUtc
}

dt.numToDate = function (num) {
	// found in mg_scripts
	return dt.unixToDate(num)
}

dt.toWeek = function (num) {
	// not called
	let date, jd
	date = dt.numToDate(num)
	jd = dt.dateToJulian(date)
	return dt.julianToWeek(jd)
}

dt.dateDifferenceToHours = function (date1, date2) {
	return (date1 - date2) / 3600000
}

dt.hoursToNum = function (hours) {
	// not called
	// return hours / 24
	return hours * 3600
}

dt.removeTimeFromDate = function (date) {
	// found in mg_scripts
	let offset
	// msInDay =  1000 * 60 * 60 * 24 #= 86400000 # Number of milliseconds in a day, 1000*86400
	offset = date.getTimezoneOffset() * 60 * 1000
	date.setTime(date.getTime() - (date.getTime() % 86400000) - offset)
}

dt.daysBetween = function (d1, d2) {
	let days
	days = d1 - d2
	days = days / 86400000 // 1000 * 60*60*24
	return days
}

dt.IsoDateTextToDate = function (txtDate) {
	let day, month, year
	// if txtDate is ""
	//  return DateTime.MinDate
	year = txtDate.substring(0, 4)
	month = txtDate.substring(5, 7)
	day = txtDate.substring(8, 10)
	return new Date(year, month - 1, day) // yes, we need -1!
}

dt.textToDate = function (fldVal, dateValue) {
	/* we need to load moment before using these
  else if fldVal.toLowerCase() is "w" # week start
  moment.locale("fi") # todo: is this needed?, auto language?
  return moment().startOf('week').toDate()
  else if fldVal.toLowerCase() is "k" # week end
  moment.locale("fi")
  date = moment().endOf('week').toDate()
  date.setDate(date.getDate() - 2) # sunday -> friday
  return date
  */
	let arr, date, day, month, tmp, year, yearNow
	if (typeof dateValue === 'string') {
		dateValue = dt.textToDate(dateValue)
	}
	if (isDate(fldVal)) {
		return fldVal
	} else if (fldVal === '' || fldVal == null) {
		return new Date(1970, 1 - 1, 1)
	} else if (fldVal.toLowerCase() === 't') {
		// today
		return new Date()
	} else if (fldVal === '-') {
		// previous day
		dateValue.setDate(dateValue.getDate() - 1)
		return dateValue
	} else if (fldVal === '+') {
		// next day
		dateValue.setDate(dateValue.getDate() + 1)
		return dateValue
	} else if (fldVal.toLowerCase() === 'y') {
		// year start
		date = new Date()
		year = date.getFullYear()
		return new Date(year, 1 - 1, 1)
	} else if (fldVal.toLowerCase() === 'r') {
		// year end
		date = new Date()
		year = date.getFullYear()
		return new Date(year, 12 - 1, 31)
	} else if (fldVal.toLowerCase() === 'm') {
		// month start
		date = new Date()
		year = date.getFullYear()
		month = date.getMonth()
		return new Date(year, month, 1)
	} else if (fldVal.toLowerCase() === 'h') {
		// month end
		date = new Date()
		year = date.getFullYear()
		month = date.getMonth() + 1
		date = new Date(year, month, 1)
		date.setDate(date.getDate() - 1)
		return date
	}
	arr = fldVal.split(/\D/) // split on anything but numbers
	day = arr[0]
	month = arr[1]
	year = arr[2]
	if (!month) {
		date = new Date()
		month = date.getMonth() + 1
		year = date.getFullYear()
	} else if (!year) {
		date = new Date()
		year = date.getFullYear()
	} else if (day.length > 2 && year.length <= 2) {
		// yyyy.mm.dd
		tmp = day
		day = year
		year = tmp
	} else if (year.length <= 2) {
		date = new Date()
		yearNow = Math.trunc(date.getFullYear() / 1000) * 1000
		year = yearNow + Number(year)
	}
	if (Number(year) < 1970) {
		year = 1970
		month = 1
		day = 1
	}
	date = new Date(year, month - 1, day)
	return date
}

dt.secondsToTimeString = function (seconds) {
	return new Date(seconds * 1000).toISOString().substr(11, 8)
}

dt.getDateFromFormat = function (date, format) {
	if (format.indexOf('/') !== -1) {
		format = format.split('/')
		date = date.split('/')
	} else if (format.indexOf('-') !== -1) {
		format = format.split('-')
		date = date.split('-')
	} else if (format.indexOf('.') !== -1) {
		format = format.split('.')
		date = date.split('.')
	} else {
		console.error('dt.getDateFromFormat, date format not valid')
		return new Date()
	}
	let year = format.indexOf('yyyy')
	let month = format.indexOf('mm')
	let day = format.indexOf('dd')
	return new Date(date[year], date[month] - 1, date[day])
}
