using System;
using System.Collections.Generic;
using System.Text;
using MarketData.MarketDataModel;
using MarketData.Utils;

namespace MarketData.Helper
{
  public class SwingTradeHelper
  {
    private SwingTradeHelper()
    {
    }
    public static SwingTrades FindSwingTrades(Prices prices,DMAPricesByDate ma21,BollingerBandElementsByDate bollingerBandElements=null)
    {
      SwingTrades swingTrades=new SwingTrades();
      if (null == prices) return swingTrades;
      prices.Sort(new PriceComparerDesc());
      for (int index = 0; index < prices.Count; index++)
      {
        SwingTrade swingTrade = FindSwing(prices, index, ma21, bollingerBandElements);
        if (null == swingTrade) continue;
        swingTrades.Add(swingTrade);
      }
      return swingTrades;
    }
    private static SwingTrade FindSwing(Prices prices, int startIndex,DMAPricesByDate ma21,BollingerBandElementsByDate bollingerBandElements=null)
    {
      if (startIndex + 4 > prices.Count) return null;
      DMAPrice maPrice = null;
      Price p = prices[startIndex];
      Price p1 = prices[startIndex + 1];
      Price p2 = prices[startIndex + 2];
      Price p3 = prices[startIndex + 3];
      if(!ma21.ContainsKey(p.Date))return null;
      maPrice = ma21[p.Date];
      if (p1.Low >= maPrice.AVGPrice) return null;
      if (!(p1.Low < p.Low && p2.Low < p1.Low && p3.Low > p2.Low)) return null;
      SwingTrade swingTrade = new SwingTrade();
      swingTrade.Symbol = p.Symbol;
      DateGenerator dateGenerator = new DateGenerator();
      if (null != bollingerBandElements && bollingerBandElements.ContainsKey(p1.Date) && bollingerBandElements.ContainsKey(p2.Date) && bollingerBandElements.ContainsKey(p3.Date))
      {
        BollingerBandElement b1=bollingerBandElements[p1.Date];
        BollingerBandElement b2=bollingerBandElements[p2.Date];
        BollingerBandElement b3 = bollingerBandElements[p3.Date];
        if (p1.Low < b1.L && p2.Low < b2.L && p3.Low > b3.L)
        {
          swingTrade.SwingType = SwingTrade.TypeOfSwing.LongBand;
          swingTrade.CandleDate = p1.Date;
          swingTrade.CandleHigh = p1.High;
          swingTrade.StopPrice = p1.Low;
          swingTrade.CloseDate = p3.Date;
          swingTrade.EntryDate = dateGenerator.FindNextBusinessDay(swingTrade.CloseDate);
          return swingTrade;
        }
      }
      DateTime? closeDate = FindCloseAboveCandle(prices, p1, startIndex + 4);
      swingTrade.SwingType = SwingTrade.TypeOfSwing.Long;
      swingTrade.CandleDate = p1.Date;
      swingTrade.CandleHigh = p1.High;
      swingTrade.StopPrice = p1.Low;
      if (null != closeDate)
      {
        swingTrade.CloseDate = closeDate.Value;
        swingTrade.EntryDate = dateGenerator.FindNextBusinessDay(swingTrade.CloseDate);
      }
      else
      {
        swingTrade.CloseDate = Utility.Epoch;
        swingTrade.EntryDate = Utility.Epoch;
      }
      if (!swingTrade.EntryDate.Equals(Utility.Epoch) && dateGenerator.DaysBetween(swingTrade.CandleDate, swingTrade.EntryDate) > 15) return null;
      return swingTrade; 
    }
    private static DateTime? FindCloseAboveCandle(Prices prices, Price priceCandle, int startIndex)
    {
      if (startIndex > prices.Count) return null;
      for (int index = startIndex; index < prices.Count; index++)
      {
        Price price = prices[index];
        if (price.Close > priceCandle.High) return price.Date;
      }
      return null;
    }
  }
}
