/*
 * Copyright (C) 2024 The LineageOS Project
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define LOG_TAG "SehRadioManager"

#include "aidl/SehRadioNetworkIndication.h"
#include "aidl/SehRadioNetworkResponse.h"
#include "hidl/SehRadioIndication.h"
#include "hidl/SehRadioResponse.h"

#include <thread>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>

#include <aidl/vendor/samsung/hardware/radio/network/ISehRadioNetwork.h>
#include <vendor/samsung/hardware/radio/2.2/ISehRadio.h>

using namespace std::chrono_literals;

using android::sp;
using android::String16;
using android::wp;
using android::base::GetIntProperty;
using android::base::ReadFileToString;
using android::base::Split;
using android::hardware::hidl_death_recipient;
using android::hardware::hidl_vec;
using android::hidl::base::V1_0::IBase;

using aidl::vendor::samsung::hardware::radio::network::ISehRadioNetwork;
using aidl::vendor::samsung::hardware::radio::network::implementation::SehRadioNetworkIndication;
using aidl::vendor::samsung::hardware::radio::network::implementation::SehRadioNetworkResponse;
using vendor::samsung::hardware::radio::V2_2::ISehRadio;
using vendor::samsung::hardware::radio::V2_2::SehVendorConfiguration;
using vendor::samsung::hardware::radio::V2_2::implementation::SehRadioIndication;
using vendor::samsung::hardware::radio::V2_2::implementation::SehRadioResponse;

using AidlVendorConfig = aidl::vendor::samsung::hardware::radio::network::SehVendorConfiguration;

template <typename C>
std::vector<C> LoadConfiguration(std::string data) {
    std::vector<C> config;

    for (std::string line : Split(data, "\n")) {
        if (line == "\0") break;

        std::vector<std::string> parts = Split(line, "=");
        if (parts.size() == 2) {
            config.push_back(C(parts[0], parts[1]));
            LOG(INFO) << line;
        } else {
            LOG(ERROR) << "Invalid data: " << line;
        }
    }

    return config;
}

bool died = false;
void onRILDDeath(void* cookie) {
    if (died) return;
    died = true;

    LOG(ERROR) << "SehRadio died, sleeping for 10s before restarting";
    std::this_thread::sleep_for(10000ms);
    exit(1);
}

struct RilHidlDeathRecipient : public hidl_death_recipient {
    void serviceDied(uint64_t cookie, const wp<IBase>& who) override { onRILDDeath((void*)cookie); }
};

static const auto gHalDeathRecipient = AIBinder_DeathRecipient_new(onRILDDeath);
static const auto gHidlHalDeathRecipient = sp<RilHidlDeathRecipient>::make();

int main() {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    ABinderProcess_startThreadPool();

    std::string content;
    if (!ReadFileToString("/vendor/etc/sehradiomanager.conf", &content)) {
        LOG(WARNING) << "Could not read config, setting defaults";
        content = "FW_READY=1";
    }

    int slotCount = GetIntProperty("ro.vendor.multisim.simslotcount", 1);
    for (int slot = 1; slot <= slotCount; slot++) {
        auto slotName = "slot" + std::to_string(slot);
        auto aidlSvcName = std::string(ISehRadioNetwork::descriptor) + "/" + slotName;
        if (AServiceManager_isDeclared(aidlSvcName.c_str())) {
            auto config = LoadConfiguration<AidlVendorConfig>(content);
            auto samsungIndication = ndk::SharedRefBase::make<SehRadioNetworkIndication>();
            auto samsungResponse = ndk::SharedRefBase::make<SehRadioNetworkResponse>();
            auto svc = ISehRadioNetwork::fromBinder(
                    ndk::SpAIBinder(AServiceManager_waitForService(aidlSvcName.c_str())));
            svc->setResponseFunctions(samsungResponse, samsungIndication);
            svc->setVendorSpecificConfiguration(0x4242, config);
            AIBinder_linkToDeath(svc->asBinder().get(), gHalDeathRecipient, 0);
            AIBinder_incStrong(svc->asBinder().get());
        } else {
            auto config = LoadConfiguration<SehVendorConfiguration>(content);
            auto samsungIndication = sp<SehRadioIndication>::make();
            auto samsungResponse = sp<SehRadioResponse>::make();
            auto svc = ISehRadio::getService(slotName);
            svc->setResponseFunction(samsungResponse, samsungIndication);
            svc->setVendorSpecificConfiguration(0x3232, hidl_vec(config));
            svc->linkToDeath(gHidlHalDeathRecipient, 0);
            svc->incStrong(gHidlHalDeathRecipient.get());
        }
        LOG(INFO) << "Done (slot" << slot << ")";
    }

    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;  // should not reach
}
