/*
 * Copyright (C) 2014-2026 CZ.NIC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QtGlobal> /* QT_VERSION_CHECK */
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
#  include <QTimeZone>
#endif /* >= Qt-6.5 */

#include "src/datovka_shared/io/db_time.h"

/*!
 * @brief Date/time format stored in desktop db.
 *
 * @note Old implementation of Datovka is likely to contain a bug.
 * Milliseconds are probably stored as microseconds.
 */
static
const QString dbFaultyDateTimeFormat("yyyy-MM-dd HH:mm:ss.000zzz");
static
const QString dbDateTimeFormat("yyyy-MM-dd HH:mm:ss.zzzttt"); // With time zone.
static
const QString dbDateTimeNoZoneFormat("yyyy-MM-dd HH:mm:ss.zzz"); // No time zone.
//static
//const QString dbShortDateTimeFormat("yyyy-MM-dd HH:mm:ss"); // No time zone.
static
const QString dbDateFormat("yyyy-MM-dd");
//static
//const QString dbDateIsoFormat("yyyy-MM-ddTHH:mm:ss.zzzttt");

static
const QString utcOffsetLiteral("+00:00");

QString qDateToDbFormat(const QDate &date)
{
	return (!date.isNull()) ? date.toString(dbDateFormat) : QString();
}

QDate dateFromDbFormat(const QString &dateDbStr)
{
	return QDate::fromString(dateDbStr, dbDateFormat);
}

QString dateStrFromDbFormat(const QString &dateDbStr, const QString &tgtFmt)
{
	QDate date = dateFromDbFormat(dateDbStr);

	if (date.isValid()) {
		return date.toString(tgtFmt);
	} else {
		return QString();
	}
}

QString qDateTimeToDbFormat(const QDateTime &dateTime)
{
	/* Convert to UTC. */
	if (!dateTime.isNull()) {
		return dateTime.toUTC().toString(
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
		/* The 'tt', 'ttt' and 'tttt' were introduced in Qt-6.5. */
		    dbDateTimeFormat
#else /* < Qt-6.5 */
		/* No need do compute timezone offset as UTC time is stored. */
		    dbDateTimeNoZoneFormat + utcOffsetLiteral
#endif /* >= Qt-6.5 */
		);
	} else {
		return QString();
	}
}

QDateTime dateTimeFromDbFormat(const QString &dateTimeDbStr)
{
	QDateTime dateTime = QDateTime::fromString(dateTimeDbStr,
	    dbDateTimeFormat);
	if (dateTime.isValid()) {
		/* Convert to local time when loaded with time zone. */
		return dateTime.toLocalTime();
	}

#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
#else /* < Qt-6.5 */
	if (dateTimeDbStr.endsWith(utcOffsetLiteral)) {
		dateTime = QDateTime::fromString(dateTimeDbStr,
		    dbDateTimeNoZoneFormat + utcOffsetLiteral);
		if (dateTime.isValid()) {
			dateTime.setTimeZone(
#  if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
			    QTimeZone::utc()
#  else /* < Qt-5.5 */
			    QTimeZone(0) /* QTimeZone() should be equivalent to QTimeZone::utc(). */
#  endif /* >= Qt-5.5 */
			);
			/* Convert to local time when loaded with time zone. */
			return dateTime.toLocalTime();
		}
	}
#endif /* >= Qt-6.5 */

	/* Try time without time zone. */
	dateTime = QDateTime::fromString(dateTimeDbStr,
	    dbDateTimeNoZoneFormat);
	if (dateTime.isValid()) {
		return dateTime;
	}

	/* Try the faulty format. */
	dateTime = QDateTime::fromString(dateTimeDbStr,
	    dbFaultyDateTimeFormat);
	if (dateTime.isValid()) {
		return dateTime;
	}

	/* Try to ignore 3 rightmost characters. */
	dateTime = QDateTime::fromString(
	    dateTimeDbStr.left(dateTimeDbStr.size() - 3),
	    dbDateTimeNoZoneFormat);

	return dateTime;
}

QString dateTimeStrFromDbFormat(const QString &dateTimeDbStr,
    const QString &tgtFmt)
{
	QDateTime dateTime = dateTimeFromDbFormat(dateTimeDbStr);

	if (dateTime.isValid()) {
		return dateTime.toString(tgtFmt);
	} else {
		return QString();
	}
}
