/*******************************************************************************
 * Copyright (c) 2026, 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 <iostream>
#include <cstring>

#include "service.h"
#include "index.h"
#include "exception.h"
#include "backend.h"

authdb::ServiceData::ServiceData(uuid::uuid sid) : AuthData(sid.value) {
    _ServiceName = nullptr;
    _HostName    = nullptr;
    _ClientId    = nullptr;
    _KrbKey      = nullptr;
    _Secret      = nullptr;
}

authdb::ServiceData::~ServiceData() {
}

void authdb::ServiceData::setServiceName(const char *name) {
    setAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                      this, &_ServiceName, "servicename", name, strlen(name) + 1);
}

const char *authdb::ServiceData::getServiceName() {
    return getAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                             this, &_ServiceName, "servicename");
}

void authdb::ServiceData::setHostName(const char *hostname) {
    setAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                      this, &_HostName, "hostname", hostname, strlen(hostname) + 1);
}

const char *authdb::ServiceData::getHostName() {
    return getAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                             this, &_HostName, "hostname");
}

void authdb::ServiceData::setClientId(const char *clientid) {
    setAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                      this, &_ClientId, "clientid", clientid, strlen(clientid) + 1);
}

const char *authdb::ServiceData::getClientId() {
    return getAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                             this, &_ClientId, "clientid");
}

void authdb::ServiceData::setSecret(const char *secret) {
    setAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                      this, &_Secret, "servicesecret", secret, strlen(secret) + 1);
}

const char *authdb::ServiceData::getSecret() {
    return getAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                             this, &_Secret, "servicesecret");
}

void authdb::ServiceData::setKrbKey(const std::string &src) {
    setAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                      this, &_KrbKey, "krbkey", src.c_str(), src.length() + 1);
}

const std::string authdb::ServiceData::getKrbKey() {
    try {
        const char *res = getAuthData<char>(DataType::ServiceData, StorageType::TextStorage,
                                            this, &_KrbKey, "krbkey");
        if (res)
            return res;
        else
            return "";
    } catch (AuthBackendError &e) {
        std::cerr << e.what() << std::endl;
        return "";
    }
}

void authdb::ServiceManager::create(AuthBackend &backend, class ServiceData *data) {
    AuthBackend::Guard guard(backend);
    int exi = 0;

    if (exits(backend, data->Data.ruid, data->getServiceName(), exi)) {
        switch (exi) {
            case 1:
                throw authdb::AuthBackendError("Create Service: Servicename already Exists aborting!");
            default:
                throw authdb::AuthBackendError("Create Service: UUID already Exists aborting!");
        }
    }

    backend.createRecord(*data, DataType::ServiceData);
}

bool authdb::ServiceManager::exits(AuthBackend &backend, const uuid::uuid &sid,
                                    const char *name, int &ret) {
    AuthBackend::Guard guard(backend, AuthBackend::Shared);
    RecordIndex &idx = backend.getIndex();
    if (!idx.valid() || idx.revision() != backend.getRevesion()) {
        idx.build(backend);
    }

    if (name && name[0] != '\0') {
        uuid::uuid found;
        if (idx.findByName(DataType::ServiceData, "servicename", name, found)) {
            ret = 1;
            return true;
        }
    }

    if (!sid.empty() && idx.findByUuid(DataType::ServiceData, sid)) {
        ret = 2;
        return true;
    }

    ret = -1;
    return false;
}

void authdb::ServiceManager::info(AuthBackend &backend, class ServiceData &dat, size_t &pos) {
    if (uuid::uuid(dat.Data.ruid).empty())
        throw AuthBackendError("service info uid required!");

    if (!backend.getRecord(dat, DataType::ServiceData))
        return;

    dat._ServiceName = &dat.Data;
}

void authdb::ServiceManager::remove(AuthBackend &backend, const uuid::uuid &sid) {
    backend.delRecord(sid.value, DataType::ServiceData);
}

void authdb::ServiceManager::edit(AuthBackend &backend, class ServiceData &dat) {
    backend.editRecord(dat, DataType::ServiceData);
}

void authdb::ServiceManager::list(AuthBackend &backend,std::vector<uuid::uuid> &uuids){
    AuthBackend::Guard guard(backend, AuthBackend::Shared);
    RecordIndex &idx = backend.getIndex();
    if(!idx.valid() || idx.revision()!=backend.getRevesion())
        idx.build(backend);
    idx.listByType(DataType::ServiceData, uuids);
}
