package top.baogutang.strategy.strategies;

import top.baogutang.strategy.commons.enums.Timeframe;
import top.baogutang.strategy.models.Kline;
import top.baogutang.strategy.models.Signal;
import top.baogutang.strategy.models.StrategyContext;
import top.baogutang.strategy.services.IndicatorService;

import java.util.*;

public class StrategyBreakoutRetestLong implements Strategy {
    private final double breakoutConfirm;
    private final double r2Low, r2High;
    private volatile boolean armed = false;
    private volatile long breakoutTime = -1;

    public StrategyBreakoutRetestLong(double breakoutConfirm, double r2Low, double r2High) {
        this.breakoutConfirm = breakoutConfirm;
        this.r2Low = r2Low;
        this.r2High = r2High;
    }

    public String name() {
        return "BreakoutRetestLong";
    }

    public Optional<Signal> evaluate(StrategyContext ctx) {
        java.util.List<Kline> h4 = ctx.getCache().lastN(Timeframe.H4, 35);
        java.util.List<Kline> m15 = ctx.getCache().lastN(Timeframe.M15, 80);
        if (h4.size() < 12 || m15.size() < 30) return Optional.empty();
        IndicatorService ind = ctx.getIndicators();
        Kline lastH4 = h4.get(h4.size() - 1);
        if (lastH4.finalBar()) {
            double avgVol = ind.smaVolume(h4, 10);
            boolean brk = lastH4.close() >= breakoutConfirm && lastH4.volume() >= avgVol * 1.3;
            if (brk) {
                armed = true;
                breakoutTime = lastH4.openTime();
            }
        }
        if (!armed) return Optional.empty();

        int barsChecked = 0;
        int holds = 0;
        double prevLow = -1;
        for (int i = m15.size() - 1; i >= 0 && barsChecked < 12; i--) {
            Kline k = m15.get(i);
            if (k.openTime() < breakoutTime) break;
            barsChecked++;
            boolean within = k.low() >= r2Low - Math.abs(r2Low) * 0.000003
                    && k.low() <= r2High + Math.abs(r2High) * 0.000003;
            if (!within) return Optional.empty();
            if (prevLow > 0 && k.low() >= prevLow * 0.999) holds++;
            prevLow = k.low();
        }
        if (barsChecked >= 4 && holds >= 2) {
            Kline last15 = m15.get(m15.size() - 1);
            double avgVol = ind.smaVolume(m15, 20);
            if (last15.volume() < avgVol * 1.5) return Optional.empty();
            armed = false;
            double entry = Math.min(last15.close(), r2Low + (r2High - r2Low) * 0.3);
            double stop = r2Low - (r2High - r2Low) * 0.8;
            double[] targets = new double[]{
                    breakoutConfirm + (r2High - r2Low) * 1.2,
                    breakoutConfirm + (r2High - r2Low) * 2.0,
                    breakoutConfirm + (r2High - r2Low) * 3.0
            };
            String cmt = "Pullback bars=" + barsChecked + " holds=" + holds + " volFactor=" + String.format("%.2f", last15.volume() / avgVol);
            Signal sig = new Signal(java.util.UUID.randomUUID().toString(),
                    ctx.getNow(), ctx.getSymbol(), name(), "LONG",
                    entry, stop, targets, "A", cmt);
            return Optional.of(sig);
        }
        return Optional.empty();
    }
}
