#include "sierrachart.h"
#include <vector>
#include <algorithm>
#include <cmath>

SCDLLName("TV Risk Reward Overlay")

// ---------------------------------------------------------------------------
// Helper: count decimal places from tick size so prices format correctly
// ---------------------------------------------------------------------------
static int GetDecimalPlaces(float tickSize)
{
    if (tickSize <= 0) return 2;
    int d = 0;
    double v = tickSize;
    while (v - floor(v) > 1e-9 && d < 8)
    {
        v *= 10.0;
        d++;
    }
    return d;
}

// ===========================================================================
//  MAIN STUDY FUNCTION
// ===========================================================================
SCSFExport scsf_TVRiskRewardOverlay(SCStudyInterfaceRef sc)
{
    // ---- INPUTS ----
    SCInputRef InAccountSize   = sc.Input[0];
    SCInputRef InRiskPercent   = sc.Input[1];
    SCInputRef InTargetRR      = sc.Input[2];
    SCInputRef InFontSize      = sc.Input[3];
    SCInputRef InTargetColor   = sc.Input[4];
    SCInputRef InStopColor     = sc.Input[5];
    SCInputRef InEntryColor    = sc.Input[6];
    SCInputRef InTextColor     = sc.Input[7];
    SCInputRef InTransparency  = sc.Input[8];
    SCInputRef InShowZones     = sc.Input[9];
    SCInputRef InShowLines     = sc.Input[10];
    SCInputRef InLineWidth     = sc.Input[11];
    SCInputRef InShowPrice     = sc.Input[12];
    SCInputRef InShowPercent   = sc.Input[13];
    SCInputRef InShowTicks     = sc.Input[14];
    SCInputRef InShowPnL       = sc.Input[15];
    SCInputRef InShowQty       = sc.Input[16];
    SCInputRef InShowRR        = sc.Input[17];
    SCInputRef InTextYOffset   = sc.Input[18];
    SCInputRef InDebugLog      = sc.Input[19];

    // ---- DEFAULTS ----
    if (sc.SetDefaults)
    {
        sc.GraphName    = "TV Risk/Reward Overlay";
        sc.AutoLoop     = 0;
        sc.UpdateAlways = 1;
        sc.GraphRegion  = 0;

        InAccountSize.Name   = "Account Size ($)";
        InAccountSize.SetFloat(5000.0f);

        InRiskPercent.Name   = "Risk (%)";
        InRiskPercent.SetFloat(2.0f);

        InTargetRR.Name      = "Target R:R Multiplier";
        InTargetRR.SetFloat(2.0f);

        InFontSize.Name      = "Font Size";
        InFontSize.SetInt(10);

        InTargetColor.Name   = "Target / Profit Color";
        InTargetColor.SetColor(RGB(38, 166, 91));

        InStopColor.Name     = "Stop / Loss Color";
        InStopColor.SetColor(RGB(239, 83, 80));

        InEntryColor.Name    = "Entry Line Color";
        InEntryColor.SetColor(RGB(149, 152, 161));

        InTextColor.Name     = "Text Color";
        InTextColor.SetColor(RGB(255, 255, 255));

        InTransparency.Name  = "Zone Transparency (0=Solid, 100=Invisible)";
        InTransparency.SetInt(75);

        InShowZones.Name     = "Show Colored Zones";
        InShowZones.SetYesNo(1);

        InShowLines.Name     = "Show Horizontal Lines";
        InShowLines.SetYesNo(1);

        InLineWidth.Name     = "Line Width";
        InLineWidth.SetInt(1);

        InShowPrice.Name     = "Show Price";
        InShowPrice.SetYesNo(1);

        InShowPercent.Name   = "Show Percent (%)";
        InShowPercent.SetYesNo(1);

        InShowTicks.Name     = "Show $ Distance";
        InShowTicks.SetYesNo(1);

        InShowPnL.Name       = "Show PnL ($)";
        InShowPnL.SetYesNo(1);

        InShowQty.Name       = "Show Qty";
        InShowQty.SetYesNo(1);

        InShowRR.Name        = "Show Risk/Reward Ratio";
        InShowRR.SetYesNo(1);

        InTextYOffset.Name   = "Text Y-Offset (Ticks)";
        InTextYOffset.SetInt(3);

        InDebugLog.Name      = "Enable Debug Logging";
        InDebugLog.SetYesNo(1);

        return;
    }

    // ---- PERSISTENT STORAGE FOR DRAWING CLEANUP ----
    std::vector<int>* pIDs = (std::vector<int>*)sc.GetPersistentPointer(0);
    if (pIDs == NULL)
    {
        pIDs = new std::vector<int>();
        sc.SetPersistentPointer(0, pIDs);
    }

    if (sc.LastCallToFunction)
    {
        for (size_t i = 0; i < pIDs->size(); i++)
            sc.DeleteACSChartDrawing(sc.ChartNumber, 0, (*pIDs)[i]);
        delete pIDs;
        sc.SetPersistentPointer(0, NULL);
        return;
    }

    if (sc.ArraySize < 1)
        return;

    bool debugOn = (InDebugLog.GetYesNo() != 0);

    // ---- PRICE FORMAT (2 decimal places) ----
    SCString priceFmt = "%.2f";

    // ---- SCAN FOR PRICE EXPANSION DRAWINGS ----
    std::vector<int> activeIDs;
    int drawIdx = 0;
    s_UseTool drawing;
    int foundCount = 0;

    SCDateTime rightEdge = sc.BaseDateTimeIn[sc.ArraySize - 1];

    while (sc.GetUserDrawnChartDrawing(sc.ChartNumber, DRAWING_PRICE_EXPANSION, drawing, drawIdx))
    {
        drawIdx++;
        foundCount++;

        // ============================================================
        //  PRICE EXPANSION = 2-POINT TOOL
        //  Click 1 (BeginValue) = Entry
        //  Click 2 (EndValue)   = Stop Loss
        //  Target is CALCULATED from R:R multiplier input
        // ============================================================
        double entry  = drawing.BeginValue;
        double stop   = drawing.EndValue;
        double target = 0;

        if (debugOn)
        {
            SCString msg;
            msg.Format("TVRR: Drawing #%d  LineNum=%d  Begin=%.4f  End=%.4f  Third=%.4f",
                       foundCount, drawing.LineNumber, drawing.BeginValue, drawing.EndValue, drawing.ThirdValue);
            sc.AddMessageToLog(msg, 0);
        }

        if (entry == 0 || stop == 0 || fabs(entry - stop) < sc.TickSize * 0.5)
        {
            if (debugOn) sc.AddMessageToLog("TVRR: Skipped — invalid or degenerate points", 0);
            continue;
        }

        double riskDist = fabs(entry - stop);
        bool isLong = (entry > stop);

        // Check if a 3rd point exists (non-zero ThirdValue distinct from both)
        if (drawing.ThirdValue != 0
            && fabs(drawing.ThirdValue - entry) > sc.TickSize * 0.5
            && fabs(drawing.ThirdValue - stop) > sc.TickSize * 0.5)
        {
            // 3-point mode: Begin=Stop, End=Target, Third=Entry
            // (re-interpret for 3-point tools like Price Projection)
            stop   = drawing.BeginValue;
            target = drawing.EndValue;
            entry  = drawing.ThirdValue;
            riskDist = fabs(entry - stop);
            isLong = (entry > stop);

            if (debugOn) sc.AddMessageToLog("TVRR: Using 3-point mode (Begin=Stop, End=Target, Third=Entry)", 0);
        }
        else
        {
            // 2-point mode: Calculate target from R:R input
            double rrMult = (double)InTargetRR.GetFloat();
            target = isLong
                ? entry + (riskDist * rrMult)
                : entry - (riskDist * rrMult);

            if (debugOn)
            {
                SCString msg;
                msg.Format("TVRR: 2-point mode  Stop=%.4f  Entry=%.4f  Target=%.4f  %s",
                           stop, entry, target, isLong ? "LONG" : "SHORT");
                sc.AddMessageToLog(msg, 0);
            }
        }

        double rewardDist = fabs(target - entry);
        if (riskDist < sc.TickSize * 0.5) continue;

        // ---- CALCULATIONS ----
        double riskAmount  = (double)InAccountSize.GetFloat() * ((double)InRiskPercent.GetFloat() / 100.0);
        double qty         = floor(riskAmount / riskDist);
        if (qty < 1.0) qty = 1.0;

        double rrRatio     = rewardDist / riskDist;
        double profitPnL   = qty * rewardDist;
        double lossPnL     = qty * riskDist;
        double stopPct     = (riskDist / entry) * 100.0;
        double targetPct   = (rewardDist / entry) * 100.0;
        int    stopTicks   = (int)round(riskDist / sc.TickSize);
        int    targetTicks = (int)round(rewardDist / sc.TickSize);

        if (debugOn)
        {
            SCString msg;
            msg.Format("TVRR: Qty=%.0f  Risk=$%.2f  Reward=$%.2f  R:R=%.2f",
                       qty, lossPnL, profitPnL, rrRatio);
            sc.AddMessageToLog(msg, 0);
        }

        // Drawing anchors
        SCDateTime leftEdge = drawing.BeginDateTime;
        // Use the rightmost DateTime among all points
        if (drawing.EndDateTime > leftEdge) leftEdge = drawing.EndDateTime;
        if (drawing.ThirdDateTime > leftEdge) leftEdge = drawing.ThirdDateTime;
        // Actually, use the EARLIEST datetime as left edge
        leftEdge = drawing.BeginDateTime;
        if (drawing.EndDateTime < leftEdge && drawing.EndDateTime != 0) leftEdge = drawing.EndDateTime;
        if (drawing.ThirdDateTime < leftEdge && drawing.ThirdDateTime != 0) leftEdge = drawing.ThirdDateTime;

        int region = drawing.Region;
        int base   = 70000 + (drawing.LineNumber * 10);
        float yOff = sc.TickSize * InTextYOffset.GetInt();

        // ================================================================
        //  PROFIT ZONE (Entry <-> Target)
        // ================================================================
        if (InShowZones.GetYesNo())
        {
            s_UseTool z;
            z.Clear();
            z.ChartNumber       = sc.ChartNumber;
            z.DrawingType       = DRAWING_RECTANGLEHIGHLIGHT;
            z.LineNumber        = base + 0;
            z.AddMethod         = UTAM_ADD_OR_ADJUST;
            z.Region            = region;
            z.BeginDateTime     = leftEdge;
            z.EndDateTime       = rightEdge;
            z.BeginValue        = entry;
            z.EndValue          = target;
            z.Color             = InTargetColor.GetColor();
            z.SecondaryColor    = InTargetColor.GetColor();
            z.TransparencyLevel = InTransparency.GetInt();
            sc.UseTool(z);
            activeIDs.push_back(base + 0);

            // LOSS ZONE (Entry <-> Stop)
            z.Clear();
            z.ChartNumber       = sc.ChartNumber;
            z.DrawingType       = DRAWING_RECTANGLEHIGHLIGHT;
            z.LineNumber        = base + 1;
            z.AddMethod         = UTAM_ADD_OR_ADJUST;
            z.Region            = region;
            z.BeginDateTime     = leftEdge;
            z.EndDateTime       = rightEdge;
            z.BeginValue        = entry;
            z.EndValue          = stop;
            z.Color             = InStopColor.GetColor();
            z.SecondaryColor    = InStopColor.GetColor();
            z.TransparencyLevel = InTransparency.GetInt();
            sc.UseTool(z);
            activeIDs.push_back(base + 1);
        }

        // ================================================================
        //  HORIZONTAL LINES
        // ================================================================
        if (InShowLines.GetYesNo())
        {
            int lw = InLineWidth.GetInt();

            s_UseTool ln;
            // Entry line
            ln.Clear();
            ln.ChartNumber  = sc.ChartNumber;
            ln.DrawingType  = DRAWING_LINE;
            ln.LineNumber   = base + 2;
            ln.AddMethod    = UTAM_ADD_OR_ADJUST;
            ln.Region       = region;
            ln.BeginDateTime = leftEdge;
            ln.EndDateTime  = rightEdge;
            ln.BeginValue   = entry;
            ln.EndValue     = entry;
            ln.Color        = InEntryColor.GetColor();
            ln.LineWidth    = lw;
            ln.LineStyle    = LINESTYLE_SOLID;
            sc.UseTool(ln);
            activeIDs.push_back(base + 2);

            // Target line
            ln.Clear();
            ln.ChartNumber  = sc.ChartNumber;
            ln.DrawingType  = DRAWING_LINE;
            ln.LineNumber   = base + 3;
            ln.AddMethod    = UTAM_ADD_OR_ADJUST;
            ln.Region       = region;
            ln.BeginDateTime = leftEdge;
            ln.EndDateTime  = rightEdge;
            ln.BeginValue   = target;
            ln.EndValue     = target;
            ln.Color        = InTargetColor.GetColor();
            ln.LineWidth    = lw;
            ln.LineStyle    = LINESTYLE_SOLID;
            sc.UseTool(ln);
            activeIDs.push_back(base + 3);

            // Stop line
            ln.Clear();
            ln.ChartNumber  = sc.ChartNumber;
            ln.DrawingType  = DRAWING_LINE;
            ln.LineNumber   = base + 4;
            ln.AddMethod    = UTAM_ADD_OR_ADJUST;
            ln.Region       = region;
            ln.BeginDateTime = leftEdge;
            ln.EndDateTime  = rightEdge;
            ln.BeginValue   = stop;
            ln.EndValue     = stop;
            ln.Color        = InStopColor.GetColor();
            ln.LineWidth    = lw;
            ln.LineStyle    = LINESTYLE_SOLID;
            sc.UseTool(ln);
            activeIDs.push_back(base + 4);
        }

        // ================================================================
        //  TEXT LABELS
        // ================================================================
        SCString tmp;
        SCString sep;

        // ---- TARGET LABEL ----
        SCString tgtText;
        sep = "";
        if (InShowPrice.GetYesNo())    { tmp.Format(priceFmt, target);      tgtText += sep; tgtText += tmp; sep = "  "; }
        if (InShowPercent.GetYesNo())   { tmp.Format("%.2f%%", targetPct);   tgtText += sep; tgtText += tmp; sep = "  "; }
        if (InShowTicks.GetYesNo())     { tmp.Format("$%.2f", rewardDist);   tgtText += sep; tgtText += tmp; sep = "  "; }
        if (InShowPnL.GetYesNo())       { tmp.Format("+$%.2f", profitPnL);   tgtText += sep; tgtText += tmp; }

        if (tgtText.GetLength() > 0)
        {
            double tgtY = isLong ? (target + yOff) : (target - yOff);
            s_UseTool t;
            t.Clear();
            t.ChartNumber  = sc.ChartNumber;
            t.DrawingType  = DRAWING_TEXT;
            t.LineNumber   = base + 5;
            t.AddMethod    = UTAM_ADD_OR_ADJUST;
            t.Region       = region;
            t.BeginDateTime = leftEdge;
            t.BeginValue   = tgtY;
            t.Color        = InTargetColor.GetColor();
            t.FontSize     = InFontSize.GetInt();
            t.FontBold     = 1;
            t.Text         = tgtText;
            sc.UseTool(t);
            activeIDs.push_back(base + 5);
        }

        // ---- ENTRY LABEL ----
        SCString entText;
        sep = "";
        if (InShowPrice.GetYesNo())  { tmp.Format(priceFmt, entry);      entText += sep; entText += tmp; sep = "  "; }
        if (InShowQty.GetYesNo())    { tmp.Format("Qty: %.0f", qty);     entText += sep; entText += tmp; sep = "  "; }
        if (InShowRR.GetYesNo())     { tmp.Format("R:R  %.2f", rrRatio); entText += sep; entText += tmp; }

        if (entText.GetLength() > 0)
        {
            s_UseTool t;
            t.Clear();
            t.ChartNumber  = sc.ChartNumber;
            t.DrawingType  = DRAWING_TEXT;
            t.LineNumber   = base + 6;
            t.AddMethod    = UTAM_ADD_OR_ADJUST;
            t.Region       = region;
            t.BeginDateTime = leftEdge;
            t.BeginValue   = entry + yOff;
            t.Color        = InTextColor.GetColor();
            t.FontSize     = InFontSize.GetInt();
            t.FontBold     = 1;
            t.Text         = entText;
            sc.UseTool(t);
            activeIDs.push_back(base + 6);
        }

        // ---- STOP LABEL ----
        SCString slText;
        sep = "";
        if (InShowPrice.GetYesNo())    { tmp.Format(priceFmt, stop);       slText += sep; slText += tmp; sep = "  "; }
        if (InShowPercent.GetYesNo())   { tmp.Format("%.2f%%", stopPct);    slText += sep; slText += tmp; sep = "  "; }
        if (InShowTicks.GetYesNo())     { tmp.Format("$%.2f", riskDist);    slText += sep; slText += tmp; sep = "  "; }
        if (InShowPnL.GetYesNo())       { tmp.Format("-$%.2f", lossPnL);    slText += sep; slText += tmp; }

        if (slText.GetLength() > 0)
        {
            double slY = isLong ? (stop - yOff) : (stop + yOff);
            s_UseTool t;
            t.Clear();
            t.ChartNumber  = sc.ChartNumber;
            t.DrawingType  = DRAWING_TEXT;
            t.LineNumber   = base + 7;
            t.AddMethod    = UTAM_ADD_OR_ADJUST;
            t.Region       = region;
            t.BeginDateTime = leftEdge;
            t.BeginValue   = slY;
            t.Color        = InStopColor.GetColor();
            t.FontSize     = InFontSize.GetInt();
            t.FontBold     = 1;
            t.Text         = slText;
            sc.UseTool(t);
            activeIDs.push_back(base + 7);
        }

    } // end while

    // Log summary on first run or when debug is on
    if (debugOn && sc.UpdateStartIndex == 0)
    {
        SCString msg;
        msg.Format("TVRR: Scan complete. Found %d Price Expansion drawing(s).", foundCount);
        sc.AddMessageToLog(msg, 0);
    }

    // ================================================================
    //  CLEANUP — remove orphaned drawings
    // ================================================================
    for (size_t i = 0; i < pIDs->size(); i++)
    {
        int oldID = (*pIDs)[i];
        if (std::find(activeIDs.begin(), activeIDs.end(), oldID) == activeIDs.end())
            sc.DeleteACSChartDrawing(sc.ChartNumber, 0, oldID);
    }
    *pIDs = activeIDs;
}