using MarketData.Generator;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using TradeBlotter.ViewModels;
using TradeBlotter.UIUtils;
using System.Collections.Specialized;
using MarketData;
using MarketData.Generator.Momentum;
using MarketData.DataAccess;
using System.CodeDom;
using MarketData.Generator.MGSHMomentum;
using TradeBlotter.Interface;

namespace TradeBlotter.Model
{
  public class MGSHPositionModelCollection : ObservableCollection<MGSHPositionModel>
  {
    public void Add(MGSHActivePositions activePositions)
    {
      List<int> slotKeys=new List<int>(activePositions.Keys);
      for(int keyIndex=0;keyIndex<slotKeys.Count;keyIndex++)
      {
        MGSHPositions slotPositions=activePositions[slotKeys[keyIndex]];
        foreach (MGSHPosition position in slotPositions) Add(new MGSHPositionModel(position, keyIndex));
      }
    }

    public void Add(MGSHPositions allPositions)
    {
      foreach (MGSHPosition position in allPositions) Add(new MGSHPositionModel(position));
    }

    public void Add(MGSHPositions hedgePositions, int slotIndex=-1)
    {
      if(null == hedgePositions)return;
      foreach (MGSHPosition position in hedgePositions) Add(new MGSHPositionModel(position, slotIndex));
    }

    public void OnCollectionChanged()
    {
      base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset,null));
    }
  }

  public class MGSHPositionModel : ModelBase, IPositionModel
  {
    private MGSHPosition position = new MGSHPosition();
    private int slot;
    private int priceChangeDirection=0;
    private double prevPrice=double.NaN;
    private DateTime lastUpdated=DateTime.Now;
    private double currentPriceLow=double.NaN;
    private double rsi3=double.NaN;

    public MGSHPositionModel()
    {
    }

    public MGSHPositionModel(MGSHPosition position, int slot)
    {
      Slot=slot;
      Symbol=position.Symbol;
      PurchaseDate=position.PurchaseDate;
      SellDate=position.SellDate;
      Shares=position.Shares;
      PurchasePrice=position.PurchasePrice;
      CurrentPrice=position.CurrentPrice;
      Volume=position.Volume;
      Return1D=position.Return1D;
      CumReturn252=position.CumReturn252;
      IDIndicator=position.IDIndicator;
      Score=position.Score;
      Velocity=position.Velocity;
      PE=position.PE;
      Beta=position.Beta;
      InitialStopLimit=position.InitialStopLimit;
      TrailingStopLimit=position.TrailingStopLimit;
      LastStopAdjustment=position.LastStopAdjustment;
      PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
      Comment=position.Comment;
    }
    public MGSHPositionModel(MGSHPosition position)
    {
      slot=-1;
      Symbol=position.Symbol;
      PurchaseDate=position.PurchaseDate;
      SellDate=position.SellDate;
      Shares=position.Shares;
      PurchasePrice=position.PurchasePrice;
      CurrentPrice=position.CurrentPrice;
      Volume=position.Volume;
      Return1D=position.Return1D;
      CumReturn252=position.CumReturn252;
      IDIndicator=position.IDIndicator;
      Score=position.Score;
      Velocity=position.Velocity;
      PE=position.PE;
      Beta=position.Beta;
      InitialStopLimit=position.InitialStopLimit;
      TrailingStopLimit=position.TrailingStopLimit;
      LastStopAdjustment=position.LastStopAdjustment;
      PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
      Comment=position.Comment;
    }

    public MGSHPosition Position
    {
      get{return position;}
      set
      {
        Slot=-1;
        Symbol=position.Symbol;
        PurchaseDate=position.PurchaseDate;
        SellDate=position.SellDate;
        Shares=position.Shares;
        PurchasePrice=position.PurchasePrice;
        CurrentPrice=position.CurrentPrice;
        Volume=position.Volume;
        Return1D=position.Return1D;
        CumReturn252=position.CumReturn252;
        IDIndicator=position.IDIndicator;
        Score=position.Score;
        Velocity=position.Velocity;
        PE=position.PE;
        Beta=position.Beta;
        InitialStopLimit=position.InitialStopLimit;
        TrailingStopLimit=position.TrailingStopLimit;
        LastStopAdjustment=position.LastStopAdjustment;
        PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
        Comment=position.Comment;
        this.position.R=position.R;
      }
    }

    private void UpdateProperties()
    {
      base.OnPropertyChanged("CurrentPrice");
      base.OnPropertyChanged("MarketValue");
      base.OnPropertyChanged("ActiveMarketValue");
      base.OnPropertyChanged("GainLoss");
      base.OnPropertyChanged("GainLossPcnt");
      base.OnPropertyChanged("Comment");
      base.OnPropertyChanged("PositionRiskPercentDecimal");
      base.OnPropertyChanged("R");
      base.OnPropertyChanged("TotalRiskExposure");
      base.OnPropertyChanged("RMultiple");


      base.OnPropertyChanged("CurrentPriceColor");
      base.OnPropertyChanged("TrailingStopLimitColor");
      base.OnPropertyChanged("InitialStopLimitColor");
      base.OnPropertyChanged("ActiveMarketValueColor");
      base.OnPropertyChanged("GainLossColor");
      base.OnPropertyChanged("GainLossPcntColor");
      base.OnPropertyChanged("RColor");
      base.OnPropertyChanged("TotalRiskExposureColor");
      base.OnPropertyChanged("RMultipleColor");

    }

    public String Symbol
    {
      get{return position.Symbol;}
      set{position.Symbol=value;base.OnPropertyChanged("Symbol");}
    }

    public String Comment
    {
      get{return position.Comment;}
      set{position.Comment=value;base.OnPropertyChanged("Comment");}
    }

    public DateTime PurchaseDate
    {
      get{return position.PurchaseDate;}
      set{position.PurchaseDate=value;base.OnPropertyChanged("PurchaseDate");}
    }

    public Brush PurchaseDateColor
    {
      get
      {
        DateGenerator dateGenerator=new DateGenerator();
        if(!dateGenerator.IsMarketOpen(PurchaseDate)) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public Brush SellDateColor
    {
      get
      {
        DateGenerator dateGenerator=new DateGenerator();
        if(!dateGenerator.IsMarketOpen(SellDate)) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public DateTime SellDate
    {
      get{return position.SellDate;}
      set{position.SellDate=value;base.OnPropertyChanged("SellDate");}
    }
    public int DaysHeld
    {
      get
      {
        DateGenerator dateGenerator=new DateGenerator();
        if(Utility.IsEpoch(SellDate))return dateGenerator.DaysBetween(PurchaseDate,DateTime.Now.Date);
        return dateGenerator.DaysBetween(PurchaseDate,SellDate);  
      }
    }
    public int Slot
    {
      get{return slot;}
      set{slot=value;base.OnPropertyChanged("Slot");}
    }
    public String SlotAsString
    {
      get
      {
        if(-1==Slot)return Constants.CONST_DASHES;
        return Slot.ToString();
      }
    }

    public double PositionRiskPercentDecimal
    {
      get
      {
        return position.PositionRiskPercentDecimal;
      }
      set
      {
        position.PositionRiskPercentDecimal=value;
        base.OnPropertyChanged("PositionRiskPercentDecimal");
      }
    }

// ************************************************************************************************************************************
// ******************************************************************** R I S K *******************************************************
// ************************************************************************************************************************************

    public double R
    {
      get
      {
        if(position.TrailingStopLimit>position.PurchasePrice)return 0.00;         // here we are considering the current risk/share which is based on our stop limit
        return position.TrailingStopLimit>position.PurchasePrice?0.00:position.PurchasePrice-position.TrailingStopLimit;
      }
    }
    public Brush RColor
    {
      get
      {
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public String RMultipleAsString
    {
      get { return Utility.FormatNumber((position.CurrentPrice - position.PurchasePrice) / (position.PurchasePrice - position.InitialStopLimit), 2, false) + "R"; }    // always based on original position risk
    }

    public double RMultiple
    {
      get{return (position.CurrentPrice-position.PurchasePrice)/(position.PurchasePrice-position.InitialStopLimit);}    // always based on original position risk
    }

    public Brush RMultipleColor
    {
      get
      {
        if (!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public double TotalRiskExposure
    {
      get{return R*position.Shares;}
    }

    public Brush TotalRiskExposureColor
    {
      get
      {
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

// ************************************************************************************************************************************
    public int DaysSinceLastStopAdjustment
    {
      get 
      {
        if(!IsActivePosition)return int.MinValue;
        DateGenerator dateGenerator=new DateGenerator();
        DateTime today=DateTime.Now;
        int daysSinceLastStopAdjustment=int.MinValue;
        if(Utility.IsEpoch(position.LastStopAdjustment)) daysSinceLastStopAdjustment=dateGenerator.DaysBetweenActual(today,position.PurchaseDate);
        else daysSinceLastStopAdjustment=dateGenerator.DaysBetweenActual(today,position.LastStopAdjustment);
        return daysSinceLastStopAdjustment; 
      }
    }

    public Brush DaysSinceLastStopAdjustmentColor
    {
      get
      {
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        int daysSinceLastStopAdjustment=DaysSinceLastStopAdjustment;
        if(int.MinValue.Equals(daysSinceLastStopAdjustment))return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if(daysSinceLastStopAdjustment>=90) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        else if(daysSinceLastStopAdjustment>=60) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);    // I made them both red because yellow and purple looked horrible
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
      }
    }

    public double Shares
    {
      get{return position.Shares;}
      set{position.Shares=value;base.OnPropertyChanged("Shares");base.OnPropertyChanged("Exposure");base.OnPropertyChanged("ActiveExposure");base.OnPropertyChanged("MarketValue");base.OnPropertyChanged("ActiveMarketValue");base.OnPropertyChanged("GainLoss");base.OnPropertyChanged("GainLossPcnt");}
    }

    public double PurchasePrice
    {
      get{return position.PurchasePrice;}
      set{position.PurchasePrice=value;base.OnPropertyChanged("PurchasePrice");base.OnPropertyChanged("Exposure");base.OnPropertyChanged("ActiveExposure");base.OnPropertyChanged("GainLoss");base.OnPropertyChanged("GainLossPcnt");}
    }

    public double CurrentPrice
    {
      get{return position.CurrentPrice;}
      set
      {
        if(position.CurrentPrice==value)return;
        position.CurrentPrice=value;
        if(double.IsNaN(prevPrice)){prevPrice=position.CurrentPrice;priceChangeDirection=0;}
        else if(prevPrice>position.CurrentPrice)priceChangeDirection=-1;
        else if(prevPrice==position.CurrentPrice)priceChangeDirection=0;
        else priceChangeDirection=1;
        prevPrice=position.CurrentPrice;
        UpdateProperties();
      }
    }

    public double RSI3
    {
      get{return rsi3;}
      set
      {
        if(rsi3==value)return;
        rsi3=value;
        base.OnPropertyChanged("RSI3");
        base.OnPropertyChanged("RSI3Color");
      }
    }

    public DateTime LastUpdated
    {
      get{return lastUpdated;}
      set{lastUpdated=value;base.OnPropertyChanged("LastUpdated");}
    }

    public Brush CurrentPriceColor
    {
      get
      {
        if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if(priceChangeDirection>0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
        else if(priceChangeDirection<0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public Brush RSI3Color
    {
      get
      {
        if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if(RSI3<10||RSI3>80)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public double Exposure
    {
      get{return Shares*PurchasePrice;}
    }

    public double ActiveExposure
    {
      get{return IsActivePosition?Exposure:0.00;}
    }

    public Brush ActiveExposureColor
    {
      get
      {
        if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public double MarketValue
    {
      get{return Shares*CurrentPrice;}
    }

    public double ActiveMarketValue
    {
      get{return IsActivePosition?MarketValue:0.00;}
    }

    public Brush ActiveMarketValueColor
    {
      get
      {
        if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if (ActiveMarketValue > Exposure) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
        else if (ActiveMarketValue < Exposure) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public long Volume
    {
      get{return position.Volume;}
      set{position.Volume=value;base.OnPropertyChanged("Volume");}
    }

    public double Return1D
    {
      get{return position.Return1D;}
      set{position.Return1D=value;base.OnPropertyChanged("Return1D");}
    }

    public double GainLoss
    {
      get{return MarketValue-Exposure;}
    }

    public Brush GainLossColor
    {
      get
      {
        if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if(GainLoss>0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
        else if(GainLoss<0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }
    public double GainLossPcnt
    {
      get{return (MarketValue-Exposure)/Exposure;}
    }

    public Brush GainLossPcntColor
    {
      get
      {
        if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if(GainLoss>0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
        else if(GainLoss<0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public double CumReturn252
    {
      get{return position.CumReturn252;}
      set{position.CumReturn252=value;base.OnPropertyChanged("CumReturn252");}
    }

    public double IDIndicator
    {
      get{return position.IDIndicator;}
      set{position.IDIndicator=value;base.OnPropertyChanged("IDIndicator");}
    }

    public double Score
    {
      get { return position.Score; }
      set { position.Score=value; base.OnPropertyChanged("Score"); }
    }

    public double Velocity
    {
      get{return position.Velocity;}
      set{position.Velocity=value;base.OnPropertyChanged("Velocity");}
    }

    public double PE
    {
      get{return position.PE;}
      set{position.PE=value;base.OnPropertyChanged("PE");}
    }

    public double Beta
    {
      get{return position.Beta;}
      set{position.Beta=value;base.OnPropertyChanged("Beta");}
    }

    public bool IsActivePosition
    {
      get{return Utility.IsEpoch(SellDate)?true:false;}
    }

    public double InitialStopLimit
    {
      get { return position.InitialStopLimit; }
      set 
      { 
        position.InitialStopLimit=value;
        base.OnPropertyChanged("InitialStopLimit");
        base.OnPropertyChanged("InitialStopLimitColor");
      }
    }

    public Brush InitialStopLimitColor
    {
      get
      {
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        if(!Utility.IsEpoch(position.LastStopAdjustment)) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);  // if we have a trailing stop then we are no longer using the initial stop
        StopLimit stopLimit=PortfolioDA.GetStopLimit(position.Symbol);
        if(null==stopLimit||!stopLimit.StopPrice.Equals(Math.Round(position.InitialStopLimit,2))) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple);
        if(currentPriceLow<=position.InitialStopLimit) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }

    public double TrailingStopLimit
    {
      get { return position.TrailingStopLimit; }
      set 
      { 
        position.TrailingStopLimit=value; 
        base.OnPropertyChanged("TrailingStopLimit"); 
        base.OnPropertyChanged("TrailingStopLimitColor");
      }
    }

    public Brush TrailingStopLimitColor
    {
      get
      {
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        StopLimit stopLimit=PortfolioDA.GetStopLimit(position.Symbol);
        if(null==stopLimit||!stopLimit.StopPrice.Equals(Math.Round(position.TrailingStopLimit,2))) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple);
        if(currentPriceLow<=position.TrailingStopLimit)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }
// ***
    public DateTime LastStopAdjustment
    {
      get { return position.LastStopAdjustment; }
      set { position.LastStopAdjustment=value; base.OnPropertyChanged("LastStopAdjustment"); }
    }

    public Brush LastStopAdjustmentColor
    {
      get
      {
        if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
      }
    }
  }
}
