using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using MarketData.DataAccess;
using MarketData.MarketDataModel;
using MarketData.Utils;

// This Beta calculator is modelled after Yahoo Finance Beta calculator.  It calculates Beta using 36 monthly prices start at beginning of previous month and going back 36 months
// While the calculator does not match exactly to Yahoo Finance I will use this as an alternative in the event that Yahoo Finance Beta is no longer available.
namespace MarketData.Numerical
{
  public class BetaPrices : List<BetaPrice>
  {
    public BetaPrices()
    {
    }
// assuming that the list is in descending date order
    public double[] ReturnsBenchmark()
    {
      double[] returns=new double[Count-1];
      for(int index=Count-2;index>=0;index--)
      {
        if(this[index+1].PriceBenchmark.Close==0.00)returns[index]=0.00;
        else returns[index]=(this[index].PriceBenchmark.Close-this[index+1].PriceBenchmark.Close)/this[index+1].PriceBenchmark.Close;
      }
      return returns;
    }
    public double[] ReturnsSymbol()
    {
      double[] returns=new double[Count-1];
      for(int index=Count-2;index>=0;index--)
      {
        if(this[index+1].PriceSymbol.Close==0.00)returns[index]=0.00;
        else returns[index]=(this[index].PriceSymbol.Close-this[index+1].PriceSymbol.Close)/this[index+1].PriceSymbol.Close;
      }
      return returns;
    }
  }
  public class BetaPrice
  {
    public BetaPrice(String symbol,String benchmark,Price symbolPrice,Price benchmarkPrice,DateTime pricingDate)
    {
      Symbol=symbol;
      Benchmark=benchmark;
      PricingDate=pricingDate;
      PriceSymbol=symbolPrice;
      PriceBenchmark=benchmarkPrice;
    }
    public DateTime PricingDate{get;set;}
    public String Symbol{get;set;}
    public String Benchmark{get;set;}
    public Price PriceSymbol{get;set;}
    public Price PriceBenchmark{get;set;}
  }

  public class BetaGenerator
  {
    private BetaGenerator()
    {
    }
    //public static double Beta(String symbol,int months = 36)
    //{
    //  return Beta(symbol, PricingDA.GetLatestDate(symbol), months);
    //}
    //public static double Beta(String symbol,DateTime asof,int months=36)
    //{
    //  try
    //  {
    //    String benchmark = "SPY";
    //    DateGenerator dateGenerator = new DateGenerator();

    //    BetaPrices betaPrices = new BetaPrices();
    //    DateTime startDate = dateGenerator.GetPrevMonthStart(asof);
    //    DateTime minPricingDate = PricingDA.GetEarliestDate(symbol);
    //    Dictionary<DateTime, Price> symbolPricesByDate = new Dictionary<DateTime, Price>();
    //    Dictionary<DateTime, Price> benchmarkPricesByDate = new Dictionary<DateTime, Price>();
    //    List<DateTime> historicalDates = new List<DateTime>();
    //    while (historicalDates.Count < (months + 1))
    //    {
    //      historicalDates.Add(startDate);
    //      startDate = dateGenerator.GetPrevMonthStart(startDate);
    //    }
    //    Prices symbolPrices = PricingDA.GetPrices(symbol, asof, historicalDates[historicalDates.Count - 1]);
    //    Prices benchmarkPrices = PricingDA.GetPrices(benchmark, asof, historicalDates[historicalDates.Count - 1]);
    //    foreach (Price price in symbolPrices) symbolPricesByDate.Add(price.Date, price);
    //    foreach (Price price in benchmarkPrices) benchmarkPricesByDate.Add(price.Date, price);
    //    startDate = dateGenerator.GetPrevMonthStart(asof);
    //    while (betaPrices.Count < (months + 1))
    //    {
    //      BetaPrice betaPrice = GetPrice(symbol, benchmark, startDate, symbolPricesByDate, benchmarkPricesByDate);
    //      if (null == betaPrice)
    //      {
    //        return double.NaN;
    //      }
    //      betaPrices.Add(betaPrice);
    //      startDate = dateGenerator.GetPrevMonthStart(startDate);
    //      if (startDate < minPricingDate) break;
    //    }
    //    double[] returnsSymbol = betaPrices.ReturnsSymbol();
    //    double[] returnsBenchmark = betaPrices.ReturnsBenchmark();
    //    double beta = Numerics.Beta(ref returnsSymbol, ref returnsBenchmark);
    //    return beta;
    //  }
    //  catch (Exception exception)
    //  {
    //    MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
    //    return double.NaN;
    //  }
    //}
    private static BetaPrice GetPrice(String symbol, String benchmark, DateTime requestedDate, Dictionary<DateTime, Price> symbolPricesByDate, Dictionary<DateTime, Price> benchmarkPricesByDate)
    {
      try
      {
        int maxAdvanceDays = 10;
        Price symbolPrice = null;
        Price benchmarkPrice = null;
        for (int advanceDays = 0; advanceDays < maxAdvanceDays; advanceDays++)
        {
          if (!symbolPricesByDate.ContainsKey(requestedDate)) { requestedDate = requestedDate.AddDays(1); continue; }
          symbolPrice = symbolPricesByDate[requestedDate];
          if (!benchmarkPricesByDate.ContainsKey(requestedDate)) { requestedDate = requestedDate.AddDays(1); continue; }
          benchmarkPrice = benchmarkPricesByDate[requestedDate];
        }
        if (null == symbolPrice || null == benchmarkPrice) return null;
        symbolPrice.Date = requestedDate.Date;
        benchmarkPrice.Date = requestedDate.Date;
        return new BetaPrice(symbol, benchmark, symbolPrice, benchmarkPrice, requestedDate);
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Exception:{0}", exception.ToString()));
        return null;
      }
    }
  }
}

