using System;
using System.Windows.Input;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading.Tasks;
using System.Windows;
using System.Linq;
using System.Text;
using MarketData;
using MarketData.Utils;
using MarketData.DataAccess;
using MarketData.MarketDataModel;
using MarketData.Generator;
using TradeBlotter.DataAccess;
using TradeBlotter.Command;
using TradeBlotter.Cache;
using TradeBlotter.Model;

namespace TradeBlotter.ViewModels
{
  public class TradeModelViewModel : WorkspaceViewModel
  {
    private RelayCommand runModelCommand;
    private List<String> watchLists;
    private String selectedWatchList;
    private List<String> symbols;
    private String selectedSymbol;
    private DateTime? selectedStartDate;
    private Items models = new Items();
    private int selectedModelIndex = 0;
    private int selectedSymbolIndex = 0;
    private double stopLossThreshold;
    private int stopLossDays;
    private double investment = 10000;
    private TradeResultList tradeResults = null;
    private ObservableCollection<TradeResultSummary> tradeResultSummary = null;
    private bool busyIndicator = false;

    public TradeModelViewModel()
    {
      DateGenerator dateGenerator=new DateGenerator();
      base.DisplayName = "TradeModel";
      PropertyChanged += OnTradeModelViewModelPropertyChanged;
      watchLists = WatchListDA.GetWatchLists();
      watchLists.Insert(0, Constants.CONST_ALL);
      selectedWatchList = watchLists.Find(x => x.Equals("Valuations"));
      models.Add(new Item("MACD(8,17,9)"));
      models.Add(new Item("MACD(12,26,9)"));
      models.Add(new Item("Swing Trade"));
      models.Add(new Item("Band Break"));
      selectedModelIndex = 0;
      selectedStartDate = new DateTime(DateTime.Now.Year, 1, 1);
      base.OnPropertyChanged("SelectedModelIndex");
      base.OnPropertyChanged("SelectedWatchList");
      base.OnPropertyChanged("SelectedSymbolIndex");
    }
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
    protected override void OnDispose()
    {
    }
    public bool BusyIndicator
    {
      get {return busyIndicator; }
      set { busyIndicator = false; }
    }
    private void OnTradeModelViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("SelectedModelIndex") || (eventArgs.PropertyName.Equals("SelectedModel") && null != selectedSymbol))
      {
      }
      else if (eventArgs.PropertyName.Equals("SelectedSymbol") || (eventArgs.PropertyName.Equals("SelectedDayCount") && null != selectedSymbol))
      {
      }
      else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
      {
//        if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = PricingDA.GetSymbols();
        if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = SymbolCache.GetInstance().GetSymbols();
        else symbols = WatchListDA.GetWatchList(selectedWatchList);
        base.OnPropertyChanged("Symbols");
        selectedSymbolIndex = 0;
        base.OnPropertyChanged("SelectedSymbolIndex");
      }
    }
    public IList<Item> Models
    {
      get
      {
        return models;
      }
    }
    public int SelectedModelIndex
    {
      get { return selectedModelIndex; }
      set
      {
        selectedModelIndex = value;
        base.OnPropertyChanged("SelectedModelIndex");
      }
    }
    public int SelectedSymbolIndex
    {
      get { return selectedSymbolIndex; }
      set
      {
        selectedSymbolIndex = value;
        base.OnPropertyChanged("SelectedSymbolIndex");
      }
    }
    public List<String> Symbols
    {
      get
      {
        return symbols;
      }
    }
    public String SelectedSymbol
    {
      get { return selectedSymbol; }
      set
      {
        if (value == selectedSymbol || String.IsNullOrEmpty(value)) return;
        selectedSymbol = value;
        selectedSymbol = selectedSymbol.ToUpper();
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public List<String> WatchListNames
    {
      get
      {
        return watchLists;
      }
      set { ;}
    }
    public String SelectedWatchList
    {
      get { return selectedWatchList; }
      set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); }
    }
    public DateTime? SelectedStartDate
    {
      get { return selectedStartDate; }
      set 
      {
        DateTime today = DateTime.Now;
        selectedStartDate = value;
        if (selectedStartDate.Value.Date >= today.Date)
        {
          MessageBox.Show("start date must be less than today", "Error");
          DateGenerator dateGenerator = new DateGenerator();
          selectedStartDate = dateGenerator.GenerateHistoricalDate(DateTime.Now, 2);
          base.OnPropertyChanged("SelectedStartDate");
          return;
        }
        base.OnPropertyChanged("SelectedStartDate"); 
      }
    }
    public double StopLossThreshold
    {
      get { return stopLossThreshold; }
      set { stopLossThreshold = value; base.OnPropertyChanged("StopLossThreshold"); }
    }
    public int StopLossDays
    {
      get { return stopLossDays; }
      set { stopLossDays = value; base.OnPropertyChanged("StopLossDays"); }
    }
    public double Investment
    {
      get { return investment; }
      set { investment = value; base.OnPropertyChanged("Investment"); }
    }
//**************************************************************************************************************************
//******************************************************** R U N  M O D E L  ***************************************************
//**************************************************************************************************************************
    public ObservableCollection<TradeBlotter.Model.TradeResult> TradeResults
    {
      get 
      {
        return null==tradeResults?null:new ObservableCollection<TradeBlotter.Model.TradeResult>(tradeResults);
      }
    }
    public ObservableCollection<TradeResultSummary> TradeResultsSummary
    {
      get
      {
        return tradeResultSummary;
      }
    }
    private void RunModel()
    {
      String selectedModel=models[selectedModelIndex].Value;
      if (selectedModel.Equals("MACD(8,17,9)") || selectedModel.Equals("MACD(12,26,9)")) RunMACDModel(selectedModel);
      else MessageBox.Show(selectedModel+" is not supported.");
    }
    private void RunMACDModel(String selctedModel)
    {
      DateGenerator dateGenerator = new DateGenerator();
      MACDSetup macdSetup = null;
      DateRange tradeDates = new DateRange(selectedStartDate.Value, DateTime.Now);
      if (double.IsNaN(stopLossThreshold)) stopLossThreshold = 0;
      try
      {
        BusyIndicator = true;
        Task workerTask = Task.Factory.StartNew(() =>
        {
          DateTime latestPricingDate = PricingDA.GetLatestDate(selectedSymbol);
          String companyName = PricingDA.GetNameForSymbol(selectedSymbol);
          if (models[selectedModelIndex].Value.Equals("MACD(8,17,9)")) macdSetup = new MACDSetup(8, 17, 9);
          else if (models[selectedModelIndex].Value.Equals("MACD(12,26,9)")) macdSetup = new MACDSetup(12, 26, 9);
          DateTime historicalDate = dateGenerator.GenerateHistoricalDate(selectedStartDate.Value, macdSetup.Slow);
          if (latestPricingDate < historicalDate)
          {
            MessageBox.Show("The historical date you are trying to run is later than the latest date for which prices are available.");
            return;
          }
          if (selectedStartDate.Value > DateTime.Now)
          {
            MessageBox.Show("The start date must be in the past.");
            return;
          }
          Dictionary<DateTime, Price> pricesByDate = new Dictionary<DateTime, Price>();
          Prices prices = PricingDA.GetPrices(selectedSymbol, DateTime.Now, historicalDate);
          Price latestPrice = prices[0];
          DateTime startDate = prices[0].Date;
          DateTime endDate = prices[prices.Count - 1].Date;
          for (int index = 0; index < prices.Count; index++) pricesByDate.Add(prices[index].Date, prices[index]);
          MACDSignals macdSignals = MACDGenerator.GenerateMACD(prices, macdSetup);
          Signals signals = SignalGenerator.GenerateSignals(macdSignals);
          Portfolio portfolio = SignalTrader.TradeSignals(tradeDates, signals, prices, investment, stopLossThreshold, stopLossDays);
          tradeResults = new TradeResultList();
          for (int index = 0; index < portfolio.Trades.Count; index++)
          {
            ModelTrade modelTrade = portfolio.Trades[index];
            TradeBlotter.Model.TradeResult tradeResult = new TradeBlotter.Model.TradeResult(modelTrade.TradeDate, modelTrade.Type.Equals(ModelTrade.TradeType.Buy) ? "Buy" : "Sell", modelTrade.Symbol, modelTrade.Shares, modelTrade.Price, modelTrade.GainLoss, modelTrade.Return,modelTrade.Exposure,modelTrade.DaysHeld, modelTrade.Comment);
            tradeResults.Add(tradeResult);
          }
          tradeResults.Sort();
          tradeResultSummary = new ObservableCollection<TradeResultSummary>();
          TradeResultSummary summary = new TradeResultSummary();
          summary.AverageGainLoss = portfolio.GetAverageGainLoss();
          summary.AverageHoldingDays = portfolio.GetAverageHoldingDays();
          summary.MaximumHoldingDays = portfolio.GetMaxHoldingDays();
          summary.MinimumHoldingDays = portfolio.GetMinHoldingDays();
          summary.PortfolioValue = portfolio.GetPortfolioValue(prices[0]);
          summary.PortfolioReturn = portfolio.GetPortfolioReturn(prices[0]);
          tradeResultSummary.Add(summary);
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          base.OnPropertyChanged("TradeResults");
          base.OnPropertyChanged("TradeResultsSummary");
        });
      }
      catch (Exception exception)
      {
        BusyIndicator = false;
        MessageBox.Show(exception.ToString());
      }
    }
    private bool CanRunModel
    {
      get
      {
        if (null == selectedSymbol) return false;
        if (null == selectedStartDate || Utility.IsEpoch(selectedStartDate.Value)) return false;
        return true;
      }
    }
    public ICommand RunModelCommand
    {
      get
      {
        if (runModelCommand == null)
        {
          runModelCommand = new RelayCommand(param => this.RunModel(), param => this.CanRunModel);
        }
        return runModelCommand;
      }
    }
  }
}
