/***********************************************************************************************************************************
Test PostgreSQL Info Handler
***********************************************************************************************************************************/
#include "common/io/bufferRead.h"
#include "common/io/bufferWrite.h"

#include "common/harnessInfo.h"
#include "common/harnessPostgres.h"

/***********************************************************************************************************************************
Test save callback
***********************************************************************************************************************************/
static void
testInfoBackupSaveCallback(void *data, const String *sectionNext, InfoSave *infoSaveData)
{
    (void)data;

    if (infoSaveSection(infoSaveData, "backup:current", sectionNext))
        infoSaveValue(infoSaveData, "backup:current", "20161219-212741F", STRDEF("{}"));

    if (infoSaveSection(infoSaveData, "db:backup", sectionNext))
        infoSaveValue(infoSaveData, "db:backup", "key", STRDEF("\"value\""));

    if (infoSaveSection(infoSaveData, "later", sectionNext))
        infoSaveValue(infoSaveData, "later", "key", STRDEF("\"value\""));
}

/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
static void
testRun(void)
{
    // *****************************************************************************************************************************
    if (testBegin("infoPgNew(), infoPgNewInternal(), infoPgSet()"))
    {
        InfoPg *infoPg = NULL;

        TEST_ASSIGN(infoPg, infoPgNew(infoPgBackup, NULL), "infoPgNew(cipherTypeNone, NULL)");
        TEST_RESULT_INT(infoPgDataTotal(infoPg), 0, "  0 history");
        TEST_RESULT_STR(infoCipherPass(infoPgInfo(infoPg)), NULL, "  cipherPass NULL");
        TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, "  0 historyCurrent");

        TEST_ASSIGN(infoPg, infoPgNew(infoPgArchive, STRDEF("123xyz")), "infoPgNew(cipherTypeAes256Cbc, 123xyz)");
        TEST_RESULT_INT(infoPgDataTotal(infoPg), 0, "  0 history");
        TEST_RESULT_STR_Z(infoCipherPass(infoPgInfo(infoPg)), "123xyz", "  cipherPass set");
        TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, "  0 historyCurrent");

        // -------------------------------------------------------------------------------------------------------------------------
        TEST_ASSIGN(
            infoPg,
            infoPgSet(
                infoPgNew(infoPgArchive, NULL), infoPgArchive, PG_VERSION_18, 6569239123849665679,
                hrnPgCatalogVersion(PG_VERSION_18)),
            "infoPgSet - infoPgArchive");
        TEST_RESULT_INT(infoPgDataTotal(infoPg), 1, "  1 history");
        TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, "  0 historyCurrent");
        InfoPgData pgData = infoPgData(infoPg, infoPgDataCurrentId(infoPg));
        TEST_RESULT_INT(pgData.id, 1, "  id set");
        TEST_RESULT_UINT(pgData.systemId, 6569239123849665679, "  system-id set");
        TEST_RESULT_UINT(pgData.version, PG_VERSION_18, "  version set");
        TEST_RESULT_UINT(pgData.catalogVersion, 0, "  catalog version not set for archive");

        TEST_ASSIGN(
            infoPg, infoPgSet(infoPg, infoPgArchive, PG_VERSION_18, 6569239123849665999, hrnPgCatalogVersion(PG_VERSION_18)),
            "infoPgSet - infoPgArchive second db");
        TEST_RESULT_INT(infoPgDataTotal(infoPg), 2, "  2 history");
        TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, "  0 historyCurrent");
        pgData = infoPgData(infoPg, infoPgDataCurrentId(infoPg));
        TEST_RESULT_INT(pgData.id, 2, "  current id updated");
        TEST_RESULT_UINT(pgData.systemId, 6569239123849665999, "  system-id updated");
        TEST_RESULT_UINT(pgData.version, PG_VERSION_18, "  version updated");
        TEST_RESULT_UINT(pgData.catalogVersion, 0, "  catalog version not set for archive");
        TEST_RESULT_STR(infoCipherPass(infoPgInfo(infoPg)), NULL, "  cipherPass not set");

        // -------------------------------------------------------------------------------------------------------------------------
        TEST_ASSIGN(
            infoPg,
            infoPgSet(
                infoPgNew(infoPgBackup, STRDEF("123xyz")), infoPgBackup, PG_VERSION_18, 6569239123849665679,
                hrnPgCatalogVersion(PG_VERSION_18)),
            "infoPgSet - infoPgBackup");
        TEST_RESULT_INT(infoPgDataTotal(infoPg), 1, "  1 history");
        TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, "  0 historyCurrent");
        pgData = infoPgData(infoPg, infoPgDataCurrentId(infoPg));
        TEST_RESULT_INT(pgData.id, 1, "  id set");
        TEST_RESULT_UINT(pgData.systemId, 6569239123849665679, "  system-id set");
        TEST_RESULT_UINT(pgData.version, PG_VERSION_18, "  version set");
        TEST_RESULT_UINT(pgData.catalogVersion, 202506291, "  catalog version updated");
        TEST_RESULT_STR_Z(infoCipherPass(infoPgInfo(infoPg)), "123xyz", "  cipherPass set");
    }

    // *****************************************************************************************************************************
    if (testBegin("infoPgNewLoad(), infoPgFree(), infoPgDataCurrent(), infoPgDataToLog(), infoPgAdd(), infoPgSave()"))
    {
        // Archive info
        // -------------------------------------------------------------------------------------------------------------------------
        const Buffer *contentLoad = harnessInfoChecksumZ(
            "[backup:current]\n"
            "20161219-212741F={}\n"
            "\n"
            "[db]\n"
            "db-id=1\n"
            "db-system-id=6569239123849665679\n"
            "db-version=\"18\"\n"
            "\n"
            "[db:backup]\n"
            "key=\"value\"\n"
            "\n"
            "[db:history]\n"
            "1={\"db-id\":6569239123849665679,\"db-version\":\"18\"}\n"
            "\n"
            "[later]\n"
            "key=\"value\"\n");

        String *callbackContent = strNew();
        InfoPg *infoPg = NULL;

        TEST_ASSIGN(
            infoPg, infoPgNewLoad(ioBufferReadNew(contentLoad), infoPgArchive, harnessInfoLoadNewCallback, callbackContent),
            "load file");
        TEST_RESULT_STR_Z(
            callbackContent,
            "[backup:current] 20161219-212741F={}\n"
            "[db:backup] key=\"value\"\n"
            "[later] key=\"value\"\n",
            "    check callback content");
        TEST_RESULT_INT(lstSize(infoPg->pub.history), 1, "    history record added");

        InfoPgData pgData = infoPgDataCurrent(infoPg);
        TEST_RESULT_INT(pgData.id, 1, "    id set");
        TEST_RESULT_UINT(pgData.version, PG_VERSION_18, "    version set");
        TEST_RESULT_UINT(pgData.systemId, 6569239123849665679, "    system-id set");
        TEST_RESULT_INT(infoPgDataTotal(infoPg), 1, "    check pg data total");
        TEST_RESULT_STR_Z(infoPgArchiveId(infoPg, 0), "18-1", "    check pg archive id");
        TEST_RESULT_STR(infoPgCipherPass(infoPg), NULL, "    no cipher passphrase");

        Buffer *contentSave = bufNew(0);

        TEST_RESULT_VOID(infoPgSave(infoPg, ioBufferWriteNew(contentSave), testInfoBackupSaveCallback, (void *)1), "info save");
        TEST_RESULT_STR(strNewBuf(contentSave), strNewBuf(contentLoad), "   check save");

        // Backup info
        // -------------------------------------------------------------------------------------------------------------------------
        #define CONTENT_DB                                                                                                         \
            "[db]\n"                                                                                                               \
            "db-catalog-version=202506291\n"                                                                                       \
            "db-control-version=1800\n"                                                                                            \
            "db-id=2\n"                                                                                                            \
            "db-system-id=6365925855999999999\n"                                                                                   \
            "db-version=\"18\"\n"

        #define CONTENT_DB_HISTORY                                                                                                 \
            "\n"                                                                                                                   \
            "[db:history]\n"                                                                                                       \
            "1={\"db-catalog-version\":20081101,\"db-control-version\":730,\"db-system-id\":6569239123849665679,"                  \
                "\"db-version\":\"7.3\"}\n"                                                                                        \
            "2={\"db-catalog-version\":202506291,\"db-control-version\":1800,\"db-system-id\":6365925855999999999,"                \
                "\"db-version\":\"18\"}\n"

        contentLoad = harnessInfoChecksumZ(
            CONTENT_DB
            "\n"
            "[backup:current]\n"
            "20161219-212741F={}\n"
            CONTENT_DB_HISTORY);

        callbackContent = strNew();

        TEST_ASSIGN(infoPg, infoPgNewLoad(ioBufferReadNew(contentLoad), infoPgBackup, NULL, NULL), "load file");
        TEST_RESULT_STR_Z(callbackContent, "", "    check callback content");

        TEST_RESULT_INT(infoPgDataTotal(infoPg), 2, "    check pg data total");

        pgData = infoPgDataCurrent(infoPg);
        TEST_RESULT_INT(pgData.id, 2, "    id set");
        TEST_RESULT_INT(pgData.version, PG_VERSION_18, "    version set");
        TEST_RESULT_UINT(pgData.systemId, 6365925855999999999, "    system-id set");

        pgData = infoPgData(infoPg, 1);
        TEST_RESULT_INT(pgData.id, 1, "    id set");
        TEST_RESULT_INT(pgData.version, 70300, "    version set");
        TEST_RESULT_INT(pgData.controlVersion, 730, "    control version set");
        TEST_RESULT_INT(pgData.catalogVersion, 20081101, "    catalog version set");
        TEST_RESULT_UINT(pgData.systemId, 6569239123849665679, "    system-id set");

        contentSave = bufNew(0);

        TEST_RESULT_VOID(infoPgSave(infoPg, ioBufferWriteNew(contentSave), NULL, NULL), "info save");
        TEST_RESULT_STR(strNewBuf(contentSave), strNewBuf(harnessInfoChecksumZ(CONTENT_DB CONTENT_DB_HISTORY)), "   check save");

        // infoPgAdd
        // -------------------------------------------------------------------------------------------------------------------------
        pgData.id = 3;
        pgData.version = PG_VERSION_96;
        pgData.systemId = HRN_PG_SYSTEMID_96;
        TEST_RESULT_VOID(infoPgAdd(infoPg, &pgData), "infoPgAdd");

        InfoPgData pgDataTest = infoPgDataCurrent(infoPg);
        TEST_RESULT_INT(pgDataTest.id, 3, "    id set");
        TEST_RESULT_INT(pgDataTest.version, PG_VERSION_96, "    version set");
        TEST_RESULT_UINT(pgDataTest.systemId, HRN_PG_SYSTEMID_96, "    system-id set");

        // infoPgDataToLog
        // -------------------------------------------------------------------------------------------------------------------------
        // test max values
        pgDataTest.id = (unsigned int)4294967295;
        pgDataTest.version = (unsigned int)4294967295;
        pgDataTest.systemId = 18446744073709551615U;
        pgDataTest.catalogVersion = 200101011;
        char logBuf[STACK_TRACE_PARAM_MAX];

        TEST_RESULT_VOID(FUNCTION_LOG_OBJECT_FORMAT(&pgDataTest, infoPgDataToLog, logBuf, sizeof(logBuf)), "infoPgDataToLog");
        TEST_RESULT_Z(
            logBuf, "{id: 4294967295, version: 4294967295, systemId: 18446744073709551615, catalogVersion: 200101011}",
            "check log");
    }
}
