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

namespace MarketData.Generator
{
// *******************************************************************************************************************************************************************
// ************************************************************ A C Q U I R E R S  M U L T I P L E  U N I T  T E S T  ************************************************
// *******************************************************************************************************************************************************************
  public class AcquirersMultipleCollection : List<AcquirersMultipleItem>
  {
    public AcquirersMultipleCollection()
    {
    }
    public AcquirersMultipleCollection(AcquirersMultipleCollection collection)
    {
      foreach(AcquirersMultipleItem acquirersMultipleItem in collection)Add(acquirersMultipleItem);
    }
  }
  public class AcquirersMultipleItem
  {
    public AcquirersMultipleItem()
    {
    }
    public String Symbol{get;set;}
    public double AcquirersMultiple{get;set;}
    public double MarketCapitalization{get;set;}
    public double EnterpriseValue{get;set;}
    public double OperatingEarnings{get;set;}
    public double DepreciationAndAmortization{get;set;}
    public double TotalRevenue{get;set;}
    public double CostOfRevenue{get;set;}
    public double SGA{get;set;}
    public double Rank{get;set;}
    public static String Heading
    {
      get{return "Symbol,MarketCapitalization,AcquirersMultiple,EnterpriseValue,OperatingEarnings,DepreciationAndAmortization,TotalRevenue,CostOfRevenue,SGA,Rank";}
    }
    public override string ToString()
    {
      StringBuilder sb=new StringBuilder();
      sb.Append(Symbol).Append(",").Append(Utility.FormatNumber(MarketCapitalization,2,false)).Append(",").Append(Utility.FormatNumber(AcquirersMultiple,2,false)).Append(",").Append(Utility.FormatNumber(EnterpriseValue,2,false)).Append(",");
      sb.Append(Utility.FormatNumber(OperatingEarnings,2,false)).Append(",").Append(Utility.FormatNumber(DepreciationAndAmortization,2,false)).Append(",");
      sb.Append(Utility.FormatNumber(TotalRevenue,2,false)).Append(",").Append(Utility.FormatNumber(CostOfRevenue,2,false)).Append(",");
      sb.Append(Utility.FormatNumber(SGA,2,false)).Append(",").Append(Utility.FormatNumber(Rank,2,false)).Append(",");
      return sb.ToString();
    }
  }
  public class AcquirersMultipleItemSorter : IComparer<AcquirersMultipleItem>
  {
    public int Compare(AcquirersMultipleItem v1,AcquirersMultipleItem v2)      // here we want to sort by lowest positive non NaN item
    {
      if(double.IsNaN(v1.AcquirersMultiple)&&double.IsNaN(v2.AcquirersMultiple))return 0;
      else if(double.IsNaN(v1.AcquirersMultiple))return -1;
      else if(double.IsNaN(v2.AcquirersMultiple))return 1;
      else if(v1.AcquirersMultiple.Equals(v2.AcquirersMultiple))return 0;
      else if(v1.AcquirersMultiple<v2.AcquirersMultiple)return 1;
      else return -1;
    }
  }
  public class AcquirersMultipeGenerator
  {
    public static AcquirersMultipleCollection ApplyRanks()
    {
      List<String> symbols=PricingDA.GetSymbols();
      return ApplyRanks(symbols);
    }
    public static AcquirersMultipleCollection ApplyRanks(String symbol)
    {
      List<String> symbols=new List<String>();
      symbols.Add(symbol);
      return ApplyRanks(symbols);
    }
    public static AcquirersMultipleCollection ApplyRanks(List<String> symbols)
    {
//      List<String> symbols=PricingDA.GetSymbols();
      AcquirersMultipleCollection acquirersMultipleCollection=new AcquirersMultipleCollection();
      IncomeStatement incomeStatement=null;
      CashflowStatement cashflowStatement=null;
      BalanceSheet balanceSheet=null;
// pull in the data for all symbols
      foreach(String symbol in symbols)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Working on {0}",symbol));
        incomeStatement=IncomeStatementDA.GetIncomeStatement(symbol,IncomeStatement.PeriodType.Annual);
        cashflowStatement=CashflowStatementDA.GetCashflowStatement(symbol,CashflowStatement.PeriodType.Annual);
        balanceSheet = BalanceSheetDA.GetBalanceSheet(symbol,BalanceSheet.PeriodType.Annual);
        Fundamental fundamental = FundamentalDA.GetFundamental(symbol);
        AcquirersMultipleItem acquirersMultipleItem=new AcquirersMultipleItem();
        acquirersMultipleItem.Symbol=symbol;
        if(null!=fundamental&&!double.IsNaN(fundamental.EnterpriseValue)&&null!=cashflowStatement&&!double.IsNaN(cashflowStatement.DepreciationAndAmortization)&&null!=incomeStatement&&!double.IsNaN(incomeStatement.TotalRevenue)&&!double.IsNaN(incomeStatement.CostOfRevenue)&&!double.IsNaN(incomeStatement.SGA))
        {
          acquirersMultipleItem.MarketCapitalization=fundamental.MarketCap;
          acquirersMultipleItem.OperatingEarnings=incomeStatement.TotalRevenue-(cashflowStatement.DepreciationAndAmortization+incomeStatement.CostOfRevenue+incomeStatement.SGA);
          acquirersMultipleItem.AcquirersMultiple=fundamental.EnterpriseValue/acquirersMultipleItem.OperatingEarnings; 
          acquirersMultipleItem.EnterpriseValue=fundamental.EnterpriseValue;
          acquirersMultipleItem.DepreciationAndAmortization=cashflowStatement.DepreciationAndAmortization;
          acquirersMultipleItem.TotalRevenue=incomeStatement.TotalRevenue;
          acquirersMultipleItem.CostOfRevenue=incomeStatement.CostOfRevenue;
          acquirersMultipleItem.SGA=incomeStatement.SGA;
        }
        else
        {
          if(null==fundamental)MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing fundamental.",symbol));
//          if(null==balanceSheet)MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing balance sheet.",symbol));
          if(null==cashflowStatement)MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing cashflow statement.",symbol));
          if(null==incomeStatement)MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing income statement.",symbol));
          if(null!=fundamental&&double.IsNaN(fundamental.EnterpriseValue))MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing fundamental data point (EnterpriseValue).",symbol));
          if(null!=cashflowStatement&&double.IsNaN(cashflowStatement.DepreciationAndAmortization))MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing cashflow statement data point (DepreciationAndAmortization).",symbol));
          if(null!=incomeStatement&&double.IsNaN(incomeStatement.CostOfRevenue))MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing income statement data point (Cost of Revenue).",symbol));
          if(null!=incomeStatement&&double.IsNaN(incomeStatement.SGA))MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} missing income statement data point (SGA).",symbol));
          acquirersMultipleItem.MarketCapitalization=double.NaN;
          acquirersMultipleItem.OperatingEarnings=double.NaN;
          acquirersMultipleItem.AcquirersMultiple=double.NaN;
          acquirersMultipleItem.EnterpriseValue=double.NaN;
          acquirersMultipleItem.DepreciationAndAmortization=double.NaN;
          acquirersMultipleItem.TotalRevenue=double.NaN;
          acquirersMultipleItem.CostOfRevenue=double.NaN;
          acquirersMultipleItem.SGA=double.NaN;
        }
        acquirersMultipleCollection.Add(acquirersMultipleItem);
      }
//  Build the rankings
      Dictionary<String,AcquirersMultipleItem> acquirersMultipleCollectionBySymbol=new Dictionary<String,AcquirersMultipleItem>();
      Dictionary<String,int> acquirersMultipleRankedByAcquirersMultiple=new Dictionary<String,int>();
      foreach(AcquirersMultipleItem acquirersMultipleItem in acquirersMultipleCollection)
      {
        if(!acquirersMultipleCollectionBySymbol.ContainsKey(acquirersMultipleItem.Symbol))acquirersMultipleCollectionBySymbol.Add(acquirersMultipleItem.Symbol,acquirersMultipleItem);
      }
      acquirersMultipleCollection.Sort(new AcquirersMultipleItemSorter());
      for(int index=0;index<acquirersMultipleCollection.Count;index++)
      {
        String symbol=acquirersMultipleCollection[index].Symbol;
        AcquirersMultipleItem acquirersMultipleItem=acquirersMultipleCollectionBySymbol[symbol];
        if(double.IsNaN(acquirersMultipleItem.AcquirersMultiple)||acquirersMultipleItem.AcquirersMultiple<=0||acquirersMultipleItem.MarketCapitalization<200000000.00||acquirersMultipleItem.EnterpriseValue<0||acquirersMultipleItem.OperatingEarnings<0)acquirersMultipleItem.Rank=0;
        else acquirersMultipleItem.Rank=index;
      }
      return acquirersMultipleCollection;
    }
// *******************************************************************************************************************************************************************
// ********************************************** A C Q U I R E R S  M U L T I P L E  G E N E R A T O R  F O R  V A L U A T I O N   **********************************
// *******************************************************************************************************************************************************************
    public static void ApplyRanks(Valuations valuations)
    {
      Dictionary<String,Valuation> valuationsBySymbol=new Dictionary<String,Valuation>();
      Dictionary<String,int> valuationsRankedByAcquirersMultiple=new Dictionary<String,int>();

      foreach(Valuation valuation in valuations)
      {
        if(!valuationsBySymbol.ContainsKey(valuation.Symbol))valuationsBySymbol.Add(valuation.Symbol,valuation);
      }
      Valuations valuationsCopyByAcquirersMultiple=new Valuations(valuations);
      valuationsCopyByAcquirersMultiple.Sort(new ValuationsByAcquirersMultiple());
      for(int index=0;index<valuationsCopyByAcquirersMultiple.Count;index++)
      {
        String symbol=valuationsCopyByAcquirersMultiple[index].Symbol;
        if(!valuationsRankedByAcquirersMultiple.ContainsKey(symbol))valuationsRankedByAcquirersMultiple.Add(symbol,index);
      }
      for(int index=0;index<valuations.Count;index++)
      {
        Valuation valuation=valuations[index];
        double acquirersMultiple=valuation.AcquirersMultiple;
        if(double.IsNaN(acquirersMultiple)||acquirersMultiple<=0||valuation.MarketCap<200000000.00||valuation.EnterpriseValue<0||valuation.OperatingEarnings<0)valuation.AMRank=0;
        else valuation.AMRank=valuationsRankedByAcquirersMultiple[valuation.Symbol];
      }
    }
  }
}
