/*
 * 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 <QMap>
#include <QPair>
#include <QString>
#include <QVector>

#include "src/datovka_shared/io/db_tables.h"
#include "src/datovka_shared/io/message_db_tables.h"

namespace MsgsTbl {
	static const QString tabName("messages");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"dmID", DB_INTEGER}, /* NOT NULL */
	{"is_verified", DB_BOOLEAN},
	{"_origin", DB_TEXT},
	{"dbIDSender", DB_TEXT},
	{"dmSender", DB_TEXT},
	{"dmSenderAddress", DB_TEXT},
	{"dmSenderType", DB_INTEGER},
	{"dmRecipient", DB_TEXT},
	{"dmRecipientAddress", DB_TEXT},
	{"dmAmbiguousRecipient", DB_TEXT},
	{"dmSenderOrgUnit", DB_TEXT},
	{"dmSenderOrgUnitNum", DB_TEXT},
	{"dbIDRecipient", DB_TEXT},
	{"dmRecipientOrgUnit", DB_TEXT},
	{"dmRecipientOrgUnitNum", DB_TEXT},
	{"dmToHands", DB_TEXT},
	{"dmAnnotation", DB_TEXT},
	{"dmRecipientRefNumber", DB_TEXT},
	{"dmSenderRefNumber", DB_TEXT},
	{"dmRecipientIdent", DB_TEXT},
	{"dmSenderIdent", DB_TEXT},
	{"dmLegalTitleLaw", DB_TEXT},
	{"dmLegalTitleYear", DB_TEXT},
	{"dmLegalTitleSect", DB_TEXT},
	{"dmLegalTitlePar", DB_TEXT},
	{"dmLegalTitlePoint", DB_TEXT},
	{"dmPersonalDelivery", DB_BOOLEAN},
	{"dmAllowSubstDelivery", DB_BOOLEAN},
	{"dmQTimestamp", DB_TEXT},
	{"dmDeliveryTime", DB_DATETIME},
	{"dmAcceptanceTime", DB_DATETIME},
	{"dmMessageStatus", DB_INTEGER},
	{"dmAttachmentSize", DB_INTEGER},
	{"_dmType", DB_TEXT}
	/*
	 * PRIMARY KEY (dmID),
	 * CHECK (is_verified IN (0, 1)),
	 * CHECK (dmPersonalDelivery IN (0, 1)),
	 * CHECK (dmAllowSubstDelivery IN (0, 1))
	*/
	};

	static const QMap<QString, QString> colConstraints = {
	    {"dmID", "NOT NULL"}
	};

	static const QString tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_dmID PRIMARY KEY (dmID),\n"
	    "        CONSTRAINT ck_is_verified CHECK (is_verified IN (0, 1)),\n"
	    "        CONSTRAINT ck_dmPersonalDelivery CHECK (dmPersonalDelivery IN (0, 1)),\n"
	    "        CONSTRAINT ck_dmAllowSubstDelivery CHECK (dmAllowSubstDelivery IN (0, 1))"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"dmID",                  {DB_INTEGER, SQLiteTbls::tr("ID")}},
	{"is_verified",           {DB_BOOLEAN, ""}},
	{"_origin",               {DB_TEXT, ""}},
	{"dbIDSender",            {DB_TEXT, ""}},
	{"dmSender",              {DB_TEXT, SQLiteTbls::tr("Sender")}},
	{"dmSenderAddress",       {DB_TEXT, SQLiteTbls::tr("Sender address")}},
	{"dmSenderType",          {DB_INTEGER, ""}},
	{"dmRecipient",           {DB_TEXT, SQLiteTbls::tr("Recipient")}},
	{"dmRecipientAddress",    {DB_TEXT, SQLiteTbls::tr("Recipient address")}},
	{"dmAmbiguousRecipient",  {DB_TEXT, ""}},
	{"dmSenderOrgUnit",       {DB_TEXT, ""}},
	{"dmSenderOrgUnitNum",    {DB_TEXT, ""}},
	{"dbIDRecipient",         {DB_TEXT, ""}},
	{"dmRecipientOrgUnit",    {DB_TEXT, ""}},
	{"dmRecipientOrgUnitNum", {DB_TEXT, ""}},
	{"dmToHands",             {DB_TEXT, SQLiteTbls::tr("To hands")}},
	{"dmAnnotation",          {DB_TEXT, SQLiteTbls::tr("Subject")}},
	{"dmRecipientRefNumber",  {DB_TEXT, SQLiteTbls::tr("Recipient reference number")}},
	{"dmSenderRefNumber",     {DB_TEXT, SQLiteTbls::tr("Sender reference number")}},
	{"dmRecipientIdent",      {DB_TEXT, SQLiteTbls::tr("Recipient file mark")}},
	{"dmSenderIdent",         {DB_TEXT, SQLiteTbls::tr("Sender file mark")}},
	{"dmLegalTitleLaw",       {DB_TEXT, SQLiteTbls::tr("Law")}},
	{"dmLegalTitleYear",      {DB_TEXT, SQLiteTbls::tr("Year")}},
	{"dmLegalTitleSect",      {DB_TEXT, SQLiteTbls::tr("Section")}},
	{"dmLegalTitlePar",       {DB_TEXT, SQLiteTbls::tr("Paragraph")}},
	{"dmLegalTitlePoint",     {DB_TEXT, SQLiteTbls::tr("Point")}},
	{"dmPersonalDelivery",    {DB_BOOLEAN, SQLiteTbls::tr("Personal delivery")}},
	{"dmAllowSubstDelivery",  {DB_BOOLEAN, SQLiteTbls::tr("Acceptance through fiction enabled")}},
	{"dmQTimestamp",          {DB_TEXT, ""}},
	{"dmDeliveryTime",        {DB_DATETIME, SQLiteTbls::tr("Delivery time")}},
	{"dmAcceptanceTime",      {DB_DATETIME, SQLiteTbls::tr("Acceptance time")}},
	{"dmMessageStatus",       {DB_INTEGER, SQLiteTbls::tr("Status")}},
	{"dmAttachmentSize",      {DB_INTEGER, SQLiteTbls::tr("Attachment size")}},
	{"_dmType",               {DB_TEXT, ""}}
	};
} /* namespace MsgsTbl */
SQLiteTbl MessageDbTables::msgsTbl(MsgsTbl::tabName, MsgsTbl::knownAttrs,
    MsgsTbl::attrProps, MsgsTbl::colConstraints, MsgsTbl::tblConstraint);

namespace FlsTbl {
	static const QString tabName("files");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"id", DB_INTEGER}, /* NOT NULL*/
	{"message_id",  DB_INTEGER},
	{"attNum", DB_INTEGER},
	{"_dmFileDescr", DB_TEXT},
	{"_dmUpFileGuid", DB_TEXT},
	{"_dmFileGuid", DB_TEXT},
	{"_dmMimeType", DB_TEXT},
	{"_dmFormat", DB_TEXT},
	{"_dmFileMetaType", DB_TEXT},
	{"_dmFileSize", DB_INTEGER},
	{"dmEncodedContent", DB_TEXT}
	/*
	 * PRIMARY KEY (id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_id PRIMARY KEY (id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"id",               {DB_INTEGER, ""}},
	{"message_id",       {DB_INTEGER, ""}},
	{"attNum",           {DB_INTEGER, ""}},
	{"_dmFileDescr",     {DB_TEXT, SQLiteTbls::tr("File name")}},
	{"_dmUpFileGuid",    {DB_TEXT, ""}},
	{"_dmFileGuid",      {DB_TEXT, ""}},
	{"_dmMimeType",      {DB_TEXT, SQLiteTbls::tr("Mime type")}},
	{"_dmFormat",        {DB_TEXT, ""}},
	{"_dmFileMetaType",  {DB_TEXT, ""}},
	{"_dmFileSize",      {DB_INTEGER, ""}},
	{"dmEncodedContent", {DB_TEXT, ""}}
	};
} /* namespace FlsTbl */
SQLiteTbl MessageDbTables::flsTbl(FlsTbl::tabName, FlsTbl::knownAttrs,
    FlsTbl::attrProps, FlsTbl::colConstraints, FlsTbl::tblConstraint);

namespace HshsTbl {
	static const QString tabName("hashes");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"id", DB_INTEGER}, /* NOT NULL */
	{"message_id", DB_INTEGER},
	{"value", DB_TEXT},
	{"_algorithm", DB_TEXT}
	/*
	 * PRIMARY KEY (id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_id PRIMARY KEY (id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"id",         {DB_INTEGER, ""}},
	{"message_id", {DB_INTEGER, ""}},
	{"value",      {DB_TEXT, ""}},
	{"_algorithm", {DB_TEXT, ""}}
	};
} /* namespace HshsTbl */
SQLiteTbl MessageDbTables::hshsTbl(HshsTbl::tabName, HshsTbl::knownAttrs,
    HshsTbl::attrProps, HshsTbl::colConstraints, HshsTbl::tblConstraint);

namespace EvntsTbl {
	static const QString tabName("events");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"id", DB_INTEGER}, /* NOT NULL */
	{"message_id", DB_INTEGER},
	{"dmEventTime", DB_TEXT},
	{"dmEventDescr", DB_TEXT}
	/*
	 * PRIMARY KEY (id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_id PRIMARY KEY (id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"id",           {DB_INTEGER, ""}},
	{"message_id",   {DB_INTEGER, ""}},
	{"dmEventTime",  {DB_TEXT, ""}},
	{"dmEventDescr", {DB_TEXT, ""}}
	};
} /* namespace EvntsTbl */
SQLiteTbl MessageDbTables::evntsTbl(EvntsTbl::tabName, EvntsTbl::knownAttrs,
    EvntsTbl::attrProps, EvntsTbl::colConstraints, EvntsTbl::tblConstraint);

namespace PrcstTbl {
	static const QString tabName("process_state");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"message_id", DB_INTEGER}, /* NOT NULL */
	{"state",      DB_INTEGER}
	/*
	 * PRIMARY KEY (message_id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints {
	    {"message_id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_message_id PRIMARY KEY (message_id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"message_id", {DB_INTEGER, ""}},
	{"state",      {DB_INTEGER, ""}}
	};
} /* namespace PrcstTbl */
SQLiteTbl MessageDbTables::prcstTbl(PrcstTbl::tabName, PrcstTbl::knownAttrs,
    PrcstTbl::attrProps, PrcstTbl::colConstraints, PrcstTbl::tblConstraint);

namespace RwmsgdtTbl {
	static const QString tabName("raw_message_data");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"message_id", DB_INTEGER}, /* NOT NULL */
	{"message_type", DB_INTEGER},
	{"data", DB_TEXT}
	/*
	 * PRIMARY KEY (message_id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"message_id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_message_id PRIMARY KEY (message_id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"message_id",   {DB_INTEGER, ""}},
	{"message_type", {DB_INTEGER, ""}},
	{"data",         {DB_TEXT, ""}}
	};
} /* namespace RwmsgdtTbl */
SQLiteTbl MessageDbTables::rwmsgdtTbl(RwmsgdtTbl::tabName,
    RwmsgdtTbl::knownAttrs, RwmsgdtTbl::attrProps, RwmsgdtTbl::colConstraints,
    RwmsgdtTbl::tblConstraint);

namespace RwdlvrinfdtTbl {
	static const QString tabName("raw_delivery_info_data");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"message_id", DB_INTEGER}, /* NOT NULL */
	{"data", DB_TEXT}
	/*
	 * PRIMARY KEY (message_id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"message_id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_message_id PRIMARY KEY (message_id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"message_id", {DB_INTEGER, ""}},
	{"data",       {DB_TEXT, ""}}
	};
} /* namespace RwdlvrinfdtTbl */
SQLiteTbl MessageDbTables::rwdlvrinfdtTbl(RwdlvrinfdtTbl::tabName,
    RwdlvrinfdtTbl::knownAttrs, RwdlvrinfdtTbl::attrProps,
    RwdlvrinfdtTbl::colConstraints, RwdlvrinfdtTbl::tblConstraint);

namespace SmsgdtTbl {
	static const QString tabName("supplementary_message_data");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"message_id", DB_INTEGER}, /* NOT NULL */
	{"message_type", DB_INTEGER},
	{"dmVODZ", DB_BOOLEAN},
	{"attsNum", DB_INTEGER},
	{"specMessFlag", DB_INTEGER},
	{"read_locally", DB_BOOLEAN},
	{"download_date", DB_DATETIME},
	{"custom_data", DB_TEXT}

	/*
	 * PRIMARY KEY (message_id),
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE,
	 * CHECK (read_locally IN (0, 1)),
	 * CHECK (dmVODZ IN (0, 1)),
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"message_id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_message_id PRIMARY KEY (message_id),\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE,\n"
	    "        CONSTRAINT ck_read_locally CHECK (read_locally IN (0, 1))"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"message_id",    {DB_INTEGER, ""}},
	{"message_type",  {DB_INTEGER, ""}},
	{"dmVODZ",        {DB_BOOLEAN, ""}},
	{"attsNum",       {DB_INTEGER, ""}},
	{"specMessFlag",  {DB_INTEGER, ""}},
	{"read_locally",  {DB_BOOLEAN, SQLiteTbls::tr("Read locally")}},
	{"download_date", {DB_DATETIME, ""}},
	{"custom_data",   {DB_TEXT, ""}}
	};
} /* namespace SmsgdtTbl */
SQLiteTbl MessageDbTables::smsgdtTbl(SmsgdtTbl::tabName, SmsgdtTbl::knownAttrs,
    SmsgdtTbl::attrProps, SmsgdtTbl::colConstraints, SmsgdtTbl::tblConstraint);

namespace CrtdtTbl {
	static const QString tabName("certificate_data");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"id", DB_INTEGER}, /* NOT NULL */
	{"der_data", DB_TEXT}
	/*
	 * PRIMARY KEY (id),
	 * UNIQUE (der_data)
	 */
	};

	static const QMap<QString, QString> colConstraints = {
	    {"id", "NOT NULL"}
	};

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT pk_id PRIMARY KEY (id),\n"
	    "        CONSTRAINT uq_der_data UNIQUE (der_data)"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"id",       {DB_INTEGER, ""}},
	{"der_data", {DB_TEXT, ""}}
	};
} /* namespace CrtdtTbl */
SQLiteTbl MessageDbTables::crtdtTbl(CrtdtTbl::tabName, CrtdtTbl::knownAttrs,
    CrtdtTbl::attrProps, CrtdtTbl::colConstraints, CrtdtTbl::tblConstraint);

namespace MsgcrtdtTbl {
	static const QString tabName("message_certificate_data");

	static const QVector< QPair<QString, enum EntryType> > knownAttrs = {
	{"message_id", DB_INTEGER},
	{"certificate_id", DB_INTEGER}
	/*
	 * FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE,
	 * FOREIGN KEY(certificate_id) REFERENCES certificate_data (id) ON DELETE CASCADE
	 */
	};

	static const QMap<QString, QString> colConstraints; /* Empty. */

	static const QString &tblConstraint(
	    ",\n"
	    "        CONSTRAINT fk_message_id FOREIGN KEY(message_id) REFERENCES messages (dmID) ON DELETE CASCADE,\n"
	    "        CONSTRAINT fk_certificate_id FOREIGN KEY(certificate_id) REFERENCES certificate_data (id) ON DELETE CASCADE"
	);

	static const QMap<QString, SQLiteTbl::AttrProp> attrProps = {
	{"message_id",     {DB_INTEGER, ""}},
	{"certificate_id", {DB_INTEGER, ""}}
	};
} /* namespace MsgcrtdtTbl */
SQLiteTbl MessageDbTables::msgcrtdtTbl(MsgcrtdtTbl::tabName,
    MsgcrtdtTbl::knownAttrs, MsgcrtdtTbl::attrProps,
    MsgcrtdtTbl::colConstraints, MsgcrtdtTbl::tblConstraint);
