//@version=6
indicator("Engulfing Pattern Breakout MTF", overlay=true, max_boxes_count=100, max_lines_count=100, max_labels_count = 100)

// =================== Inputs ===================
// Group: Pattern Detection
group_pattern = "Pattern Detection Settings"
htfInput = input.timeframe("", "Higher Timeframe (Leave empty for chart TF)", group = group_pattern)
showEngulfingShape = input.bool(true, "Show Engulfing Markers", group = group_pattern)

// Group: Visuals
group_visuals = "Visual Settings"
showRectangle = input.bool(true, "Show Engulfing Range Rectangle", group = group_visuals)
showMidLine = input.bool(true, "Show Range Midpoint Line (POC Proxy)", group = group_visuals)
showBreakoutLabel = input.bool(true, "Show Breakout Labels", group = group_visuals)

bullColor = input.color(color.new(color.green, 70), "Bullish Color", group = group_visuals)
bearColor = input.color(color.new(color.red, 70), "Bearish Color", group = group_visuals)
midLineColor = input.color(color.new(color.blue, 50), "Midpoint Line Color", group = group_visuals)
midLineStyleOption = input.string("Dashed", "Midpoint Line Style", options=["Solid", "Dotted", "Dashed"], group = group_visuals)
breakoutLabelColor = input.color(color.new(color.orange, 0), "Breakout Label Color", group = group_visuals)

// =================== Data Structure ===================
type EngulfingInfo
    int id
    int detectedBarIndex
    float rangeHigh
    float rangeLow
    bool isBullish
    box rectangle
    line midLine
    bool isBroken
    label breakoutLabel

// =================== Variables ===================
var engulfingPatterns = array.new<EngulfingInfo>()
var int patternIdCounter = 0

getLineStyle(styleString) =>
    switch styleString
        "Solid"  => line.style_solid
        "Dotted" => line.style_dotted
        "Dashed" => line.style_dashed
        => line.style_solid

midLineStyle = getLineStyle(midLineStyleOption)

// =================== MTF Data Fetching ===================
useHtf = htfInput != ""
targetTimeframe = useHtf ? htfInput : timeframe.period
[htfOpen, htfHigh, htfLow, htfClose, htfTime] = request.security(syminfo.tickerid, targetTimeframe, [open, high, low, close, time], lookahead=barmerge.lookahead_on)

// =================== Engulfing Detection Logic ===================
isBullishEngulfing(o, c, o1, c1) =>
    o1 > c1 and c > o and c > o1 and o < c1

isBearishEngulfing(o, c, o1, c1) =>
    c1 > o1 and o > c and o > c1 and c < o1

htfOpen1 = htfOpen[1]
htfClose1 = htfClose[1]
isNewHtfBar = ta.change(htfTime) != 0

bullEngulfingDetected = isNewHtfBar and isBullishEngulfing(htfOpen, htfClose, htfOpen1, htfClose1)
bearEngulfingDetected = isNewHtfBar and isBearishEngulfing(htfOpen, htfClose, htfOpen1, htfClose1)

// =================== Pattern Management ===================
if bullEngulfingDetected or bearEngulfingDetected
    patternIdCounter += 1
    float midPoint = (htfHigh + htfLow) / 2
    bool isBull = bullEngulfingDetected

    box_ = showRectangle ? box.new(
      left = bar_index,
      top = htfHigh,
      right = bar_index + 1,
      bottom = htfLow,
      bgcolor = isBull ? bullColor : bearColor,
      border_color = na,
      extend = extend.right
    ) : na

    line_ = showMidLine ? line.new(
      x1 = bar_index,
      y1 = midPoint,
      x2 = bar_index + 1,
      y2 = midPoint,
      color = midLineColor,
      style = midLineStyle,
      width = 1,
      extend = extend.right
    ) : na

    newPattern = EngulfingInfo.new(
      id = patternIdCounter,
      detectedBarIndex = bar_index,
      rangeHigh = htfHigh,
      rangeLow = htfLow,
      isBullish = isBull,
      rectangle = box_,
      midLine = line_,
      isBroken = false,
      breakoutLabel = na
    )
    engulfingPatterns.push(newPattern)

// =================== Check Breakouts and Manage Objects ===================
if engulfingPatterns.size() > 0
    for i = engulfingPatterns.size() - 1 to 0 by -1
        pattern = engulfingPatterns.get(i)

        if pattern.isBroken
            continue

        breakCondition = false
        labelText = ""

        if pattern.isBullish and close > pattern.rangeHigh
            breakCondition := true
            labelText := "▲ Breakout"
        else if not pattern.isBullish and close < pattern.rangeLow
            breakCondition := true
            labelText := "▼ Breakout"

        if breakCondition
            pattern.isBroken := true

            if showRectangle and not na(pattern.rectangle)
                pattern.rectangle.set_extend(extend.none)
                pattern.rectangle.set_right(bar_index)
            if showMidLine and not na(pattern.midLine)
                pattern.midLine.set_extend(extend.none)
                pattern.midLine.set_x2(bar_index)

            if showBreakoutLabel
                labelY = pattern.isBullish ? pattern.rangeHigh : pattern.rangeLow
                labelStyle = pattern.isBullish ? label.style_label_down : label.style_label_up
                newLabel = label.new(bar_index, labelY, labelText,
                  color = color.new(color.black, 100),
                  textcolor = breakoutLabelColor,
                  style = labelStyle,
                  size = size.small)
                pattern.breakoutLabel := newLabel

// =================== Plot Shapes (Fixed) ===================
plotshape(
  showEngulfingShape and bullEngulfingDetected,
  title = "Bullish Engulfing",
  location = location.belowbar,
  color = color.green,
  style = shape.triangleup,
  size = size.small
)

plotshape(
  showEngulfingShape and bearEngulfingDetected,
  title = "Bearish Engulfing",
  location = location.abovebar,
  color = color.red,
  style = shape.triangledown,
  size = size.small
)