/*******************************************************************************
 * Copyright (c) 2025, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <memory>
#include <cstring>
#include <vector>
#include <string>

#include <netplus/crypto/base64.h>
#include <uuidp.h>

#include "export.h"
#include "types.h"

namespace authdb {

    json_object* Export::toJson(AuthBackend &backend) {
        AuthBackend::Guard guard(backend, AuthBackend::Shared);
        json_object *jroot = json_object_new_object();
        json_object *jarr  = json_object_new_array();

        size_t rd = sizeof(AuthHeader), end = backend.end();

        while (rd + sizeof(AuthData::Record) <= end) {
            std::shared_ptr<AuthData::Record> cur = std::make_shared<AuthData::Record>();
            cur->type = EmptyData;
            backend.setPos(rd);
            backend.read(reinterpret_cast<unsigned char*>(cur.get()), sizeof(AuthData::Record));
            size_t next = backend.getPos() + cur->datasize;
            if(next < backend.getPos() || next > end) break;
            rd = next;

            // Skip empty/deleted records
            if (cur->type == EmptyData)
                continue;

            // Read record data
            std::vector<char> rawdata;
            if (cur->datasize > 0) {
                rawdata.resize(cur->datasize);
                backend.read(reinterpret_cast<unsigned char*>(rawdata.data()), cur->datasize);
            }

            // Build JSON record
            json_object *jrec = json_object_new_object();

            // ruid as uuid string
            json_object_object_add(jrec, "ruid",
                json_object_new_string(uuid::uuid(cur->ruid).c_str()));

            json_object_object_add(jrec, "type",
                json_object_new_int(cur->type));

            json_object_object_add(jrec, "storage",
                json_object_new_int(cur->storage));

            json_object_object_add(jrec, "fieldname",
                json_object_new_string(cur->fieldname));

            json_object_object_add(jrec, "datasize",
                json_object_new_int64(static_cast<int64_t>(cur->datasize)));

            // Base64 encode the data
            if (!rawdata.empty()) {
                netplus::base64 b64;
                b64 << rawdata;
                const std::vector<unsigned char> &enc = b64.encoded();
                std::string encoded(enc.begin(), enc.end());
                json_object_object_add(jrec, "data",
                    json_object_new_string(encoded.c_str()));
            } else {
                json_object_object_add(jrec, "data",
                    json_object_new_string(""));
            }

            json_object_array_add(jarr, jrec);
        }

        json_object_object_add(jroot, "version", json_object_new_int(VERSION));
        json_object_object_add(jroot, "records", jarr);

        return jroot;
    }
};

