/** --- Phi Technologies --- */
#include "../libphitech/helpers.h"
#include "sierrachart.h"

SCDLLName("PhitechBacktest");

namespace pth = phitech::helpers;

// In the study we use lowercase var names (with _) to distinguish them from Sierra's symbols.
SCSFExport scsf_TriggerBacktest(SCStudyInterfaceRef sc)
{
    SCInputRef i_date_ranges = sc.Input[0];
    SCInputRef i_replay_speed = sc.Input[1];
    SCInputRef i_enabled = sc.Input[2];

    if (sc.SetDefaults)
    {
        sc.GraphName = "Trigger Backtest";
        sc.StudyDescription = "Phi Technologies study for Sierra.";
        sc.AutoLoop = 0;
        sc.GraphRegion = 0;

        i_date_ranges.Name = "Date Ranges";
        i_date_ranges.SetString(
            "2024-09-09 13:00:00/2024-09-09 13:30:00|2024-09-09 14:00:00/2024-09-09 14:30:00");

        i_replay_speed.Name = "Replay Speed";
        i_replay_speed.SetFloat(60.0);

        i_enabled.Name = "Enabled";
        i_enabled.SetYesNo(true);
        return;
    }

    int& current_range_index = sc.GetPersistentInt(0);
    int pkey_date_ranges = 1;
    std::vector<SCDateTime>* date_ranges =
        (std::vector<SCDateTime>*)sc.GetPersistentPointer(pkey_date_ranges);

    if (sc.LastCallToFunction)
    {
        pth::print(sc, "last call to function");
        if (date_ranges != nullptr)
        {
            delete date_ranges;
            sc.SetPersistentPointer(pkey_date_ranges, nullptr);
        }
        return;
    }

    if (not i_enabled.GetYesNo())
        return;

    if (sc.Index == 0 and not sc.IsReplayRunning())
    {
        if (date_ranges == nullptr)
        {
            pth::print(sc, "backtest started");
            current_range_index = 0;

            pth::print(sc, "init ranges");
            std::vector<SCDateTime> _date_ranges;
            pth::string_to_datetime_vector(i_date_ranges.GetString(), _date_ranges);
            date_ranges = new std::vector<SCDateTime>(_date_ranges);

            pth::print(sc, "ranges to run for...");
            for (const auto& current : *date_ranges)
                pth::print(sc, sc.DateTimeToString(current, FLAG_DT_COMPLETE_DATETIME).GetChars());

            if (date_ranges != nullptr)
				sc.SetPersistentPointer(pkey_date_ranges, date_ranges);
            else
                return;

            pth::print(sc, "init complete");
        }

        if (date_ranges->size() < 2)
        {
            pth::print(sc, "ERROR: ranges need to be at least 2");
            return;
        }
    }

    SCDateTime start = (*date_ranges)[current_range_index];
    SCDateTime end = (*date_ranges)[current_range_index + 1];

    if (sc.IsReplayRunning() and sc.GetCurrentDateTime() >= end)
    {
        pth::print(sc, "end datetime reached for index -> %d", current_range_index);
		pth::print(sc, "current backtest finished");
		sc.StopChartReplay(sc.ChartNumber);

        current_range_index += 2;
        if (current_range_index >= date_ranges->size())
        {
		    pth::print(sc, "last backtest finished");
            if (date_ranges != nullptr)
            {
                delete date_ranges;
                sc.SetPersistentPointer(pkey_date_ranges, nullptr);
            }
            i_enabled.SetYesNo(false);
            return;
        }
    }

    if (sc.IsReplayRunning())
        return;

    pth::print(sc, "stop previous replay", current_range_index);
    sc.StopChartReplay(sc.ChartNumber);

    pth::print(sc, "start replay for current index -> %d", current_range_index);
    sc.StartChartReplay(sc.ChartNumber, i_replay_speed.GetFloat(), start);
}
