using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using MarketData.MarketDataModel;
using MarketData.Utils;
using MarketData.DataAccess;
using MarketData.Numerical;
using MarketData.Cache;

namespace MarketData.Generator.ModelGenerators
{
  public class EdgeRatioGenerator
  {
    private EdgeRatioGenerator()
    {
    }
    public static EdgeRatioResult CalculateEdgeRatio(String symbol,DateTime purchaseDate,double purchasePrice,DateTime asOf)
    {
      EdgeRatioResult edgeRatioResult=new EdgeRatioResult();
      DateGenerator dateGenerator=new DateGenerator();
      DateTime lastBusinesDate=dateGenerator.GetPrevBusinessDay(asOf);
      Dictionary<DateTime,TrueRangeResult> trueRangeResults=new Dictionary<DateTime,TrueRangeResult>(); 
      double[] mae=null;
      double[] mfe=null;
      double[] atr=null;

      try
      {
        List<DateTime> seriesDates=dateGenerator.GenerateHistoricalDates(purchaseDate,asOf);
        mae=new double[seriesDates.Count];
        mfe=new double[seriesDates.Count];
        atr=new double[seriesDates.Count];
        double sumMAEPlusATR=0.00;
        double sumMFEPlusATR=0.00;
        double averageMAE=0.00;
        double averageMFE=0.00;

        asOf=dateGenerator.GetPrevBusinessDay(asOf);
        for(int index=0;index<seriesDates.Count;index++)
        {
          DateTime seriesDate=seriesDates[index];
          Price seriesPrice=null;
          if(seriesDate.Date.Equals(lastBusinesDate.Date))seriesPrice=PricingDA.GetPrice(symbol,seriesDate);   // ensure we always get a hot price for last business date, other price may originate from cache
          else seriesPrice=GBPriceCache.GetInstance().GetPrice(symbol,seriesDate);
          if(null==seriesPrice)
          {
              edgeRatioResult.Message=String.Format("Price not available for {0} on {1}",symbol,seriesDate.ToShortDateString());
              return edgeRatioResult;
          }
          mfe[index]=(seriesPrice.High-purchasePrice)<0.00?0.00:(seriesPrice.High-purchasePrice);
          mae[index]=(purchasePrice-seriesPrice.Low)<0.00?0.00:(purchasePrice-seriesPrice.Low);
          atr[index]=TrueRangeGenerator.GenerateAverageTrueRange(symbol,seriesDate).AverageTrueRange;
        }
        for(int index=0;index<seriesDates.Count;index++)
        {
          sumMAEPlusATR+=(mae[index]+atr[index]);
          sumMFEPlusATR+=(mfe[index]+atr[index]);
        }
        averageMAE=sumMAEPlusATR/(double)seriesDates.Count;
        averageMFE=sumMFEPlusATR/(double)seriesDates.Count;
        edgeRatioResult.EdgeRatio=averageMFE/averageMAE;
        edgeRatioResult.Success=true;
        edgeRatioResult.Message=String.Format("EdgeRatio for {0} purchased on {1} @ {2} from {3} -> {4}",symbol,purchaseDate.ToShortDateString(),Utility.FormatCurrency(purchasePrice),purchaseDate.ToShortDateString(),asOf.ToShortDateString());
        return edgeRatioResult;
      }
      catch(Exception exception)
      {
        edgeRatioResult.Message=exception.ToString();
        return edgeRatioResult;
      }
    }
  }

  public class EdgeRatioResult
  {
    public EdgeRatioResult()
    {
      Success=false;
      EdgeRatio=double.NaN;
      Message=null;
    }
    public double EdgeRatio{get;set;}
    public bool Success{get;set;}
    public String Message{get;set;}
  }
}
