﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WhiteLightCommon;
using WhiteLightCommon.Utils;

namespace BackTester.Strategies
{
    public class MomoStrategy : BaseStrategy
    {
        private bool lookingForBuy = true;
        private bool lookingForSell = false;
        private int lastBoughtIndex = 0;
        private double lastStopLoss = 0;
        private double lastTarget = 0;
        private double nextTriggerPoint = -1;
        private int triggeredIndex = 0;

        public override string getName()
        {
            return "Momo Long";
        }

        public override StrategyBuyActionInfo shouldBuy(int index)
        {
            var strategyBuyActionInfo = new StrategyBuyActionInfo();

            if (!lookingForBuy)
            {
                return strategyBuyActionInfo;
            }

            if (index < (data.Count - 2))
            {
                if (((index != data.Count - 1) && isEarningsDay(data[index + 1].date)) || isEarningsDay(data[index].date))
                {
                    return strategyBuyActionInfo;
                }
            }

            if (isLongSignalTriggered(index, data))
            {
                return strategyBuyActionInfo;
            }

            return tryLong(index, data);
        }

        public override StrategySellActionInfo shouldSell(int index)
        {
            var result = new StrategySellActionInfo();

            if (!lookingForSell || lastBoughtIndex == index)
            {
                return result;
            }

            if ((index < (data.Count - 1)) && isEarningsDay(data[index + 1].date))
            {
                result.sellPrice = data[index].close;
                lookingForBuy = true;
                lookingForSell = false;
                result.shouldSell = true;
                return result;
            }

            if (data[index].low <= lastStopLoss)
            {
                var sellPrice = lastStopLoss;
                if (data[index].open < lastStopLoss)
                {
                    sellPrice = (data[index].low + data[index].open) / 2;
                }
                result.sellPrice = sellPrice;

                lookingForBuy = true;
                lookingForSell = false;
                result.shouldSell = true;
                return result;
            }

            if ((data[index].high >= lastTarget))
            {
                var sellPrice = lastTarget;
                if (data[index].open > lastTarget)
                {
                    sellPrice = data[index].open;
                }
                result.sellPrice = sellPrice;
                lookingForBuy = true;
                lookingForSell = false;
                result.shouldSell = true;
                return result;
            }

            return result;
        }

        private bool isLongSignalTriggered(int index, StockData data)
        {
            if (AlgoUtils.isFirstRedDay(index, data))
            {
                nextTriggerPoint = getHigh(index, 3, data);
                triggeredIndex = index;
                return true;
            }
            return false;
        }

        private bool isReadyToBeBought(int index, StockData data)
        {
            if (!spyRegimeFilter.DoesDayBelongsToRegime(data[index].date, SPYRegimeFilterType.Momentum))
            {
                return false;
            }

            //if (!isVixRegimeGreen(data[index - 1].date))
            //{
            //    return false;
            //}

            return true;
        }

        private StrategyBuyActionInfo tryLong(int index, StockData data)
        {
            var strategyBuyActionInfo = new StrategyBuyActionInfo();

            if (nextTriggerPoint == -1)
            {
                return strategyBuyActionInfo;
            }

            var todayHigh = data[index].high;
            var todayLow = data[index].low;

            if (nextTriggerPoint >= todayLow && nextTriggerPoint <= todayHigh)
            {
                if (!isReadyToBeBought(index, data))
                {
                    return strategyBuyActionInfo;
                }

                strategyBuyActionInfo.buyPrice = nextTriggerPoint;
                strategyBuyActionInfo.stopLoss = AlgoUtils.getLow(index, 3, data);
                lastStopLoss = strategyBuyActionInfo.stopLoss;
                lastTarget = nextTriggerPoint + (3 * (nextTriggerPoint - lastStopLoss));
                lastBoughtIndex = index;
                lookingForSell = true;
                lookingForBuy = false;
                strategyBuyActionInfo.shouldBuy = true;
                nextTriggerPoint = -1;

                return strategyBuyActionInfo;
            }
            else
            {
                if ((index - triggeredIndex) >= 3)
                {
                    nextTriggerPoint = -1;
                }
            }

            return strategyBuyActionInfo;
        }
    }
}