// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.

#ifndef WOWLET_RESTOREHEIGHTLOOKUP_H
#define WOWLET_RESTOREHEIGHTLOOKUP_H

#include <cstdio>
#include <cstdlib>

#include <monero_seed/monero_seed.hpp>

#include "networktype.h"
#include "utils/utils.h"

struct RestoreHeightLookup {
    NetworkType::Type type;
    QMap<int, int> data;
    explicit RestoreHeightLookup(NetworkType::Type type) : type(type) {}

    int dateToRestoreHeight(int date) {
        // restore height based on a given timestamp using a lookup
        // table. If it cannot find the date in the lookup table, it
        // will calculate the blockheight based off the last known
        // date: ((now - lastKnownDate) / blockTime) - clearance

        if(this->type == NetworkType::TESTNET) return 1;
        int blockTime = 300;
        int blocksPerDay = 288;
        int blockCalcClearance = blocksPerDay * 5;
        QList<int> values = this->data.keys();
        if(date <= values.at(0))
            return this->data[values.at(0)];
        for(int i = 0; i != values.count(); i++) {
            if(values[i] > date) {
                return i - 1 < 0 ? this->data[values[i]] : this->data[values[i-1]] - blockCalcClearance;
            }
        }

        // lookup failed, calculate blockheight from last known checkpoint
        int lastBlockHeightTime = values.at(values.count() - 1);
        int lastBlockHeight = this->data[lastBlockHeightTime];
        int deltaTime = date - lastBlockHeightTime;
        int deltaBlocks = deltaTime / blockTime;
        int blockHeight = (lastBlockHeight + deltaBlocks) - blockCalcClearance;
        qDebug() << "Calculated blockheight: " << blockHeight << " from epoch " << date;
        return blockHeight;
    }

    int restoreHeightToDate(int height) {
        // @TODO: most likely inefficient, refactor
        QMap<int, int>::iterator i;
        int timestamp = 0;
        for (i = this->data.begin(); i != this->data.end(); ++i) {
            int ts = i.key();
            if (i.value() > height)
                return timestamp;
            timestamp = ts;
        }
        return timestamp;
    }

    static RestoreHeightLookup *fromFile(const QString &fn, NetworkType::Type type) {
        // initialize this class using a lookup table, e.g `:/assets/restore_heights_monero_mainnet.txt`/
        auto rtn = new RestoreHeightLookup(type);
        auto data = Utils::barrayToString(Utils::fileOpen(fn));
        QMap<int, int> _data;
        for(const auto &line: data.split('\n')) {
            if(line.trimmed().isEmpty()) continue;
            auto spl = line.trimmed().split(':');
            rtn->data[spl.at(0).toUInt()] = spl.at(1).toUInt();
        }
        return rtn;
    }
};

#endif //WOWLET_RESTOREHEIGHTLOOKUP_H
