﻿using System;
using System.Collections.Generic;
using ForexFramework.DataFeed;
using ForexFramework.OrderManager;
using ForexFramework.Position;

namespace ForexFramework
{
    public class TickSimulator : IDataFeed, IOrderManager
    {
        readonly IEnumerable<Tick> _tickStream = null;
        readonly Tick[] _ticks = null;
        readonly DateTime _startTime;
        readonly Ticker.SourceCollection _sources = new Ticker.SourceCollection();

        public TickSimulator(Tick[] ticks, DateTime startTime)
        {
            _ticks = ticks;
            _startTime = startTime;
        }

        public TickSimulator(IEnumerable<Tick> tickStream, DateTime startTime)
        {
            _tickStream = tickStream;
            _startTime = startTime;
        }


        public struct Tick
        {
            public int PairId { get; set; }
            public DateTime Time { get; set; }
            public double Bid { get; set; }
            public double Ask { get; set; }
        }

        public void Start()
        {
            var nextSecond = _startTime;
            var oneSecond = TimeSpan.FromSeconds(1);

            if (_ticks != null)
            {
                foreach (var tick in _ticks)
                {
                    nextSecond = ProcessTick(nextSecond, tick, oneSecond);
                }
            }
            else
            {
                foreach (var tick in _tickStream)
                {
                    nextSecond = ProcessTick(nextSecond, tick, oneSecond);
                }
            }
        }

        private DateTime ProcessTick(DateTime nextSecond, Tick tick, TimeSpan oneSecond)
        {
            while (nextSecond <= tick.Time)
            {
                CurrentTime = nextSecond;
                _sources.SetTime(nextSecond);
                if (Second != null) Second(nextSecond);

                nextSecond += oneSecond;
            }

            CurrentTime = tick.Time;
            _sources.SetTime(nextSecond);
            _sources[tick.PairId].CreateTick(new TickArgs(tick.Time, tick.Bid, tick.Ask));
            return nextSecond;
        }

        public Ticker GetTicker(int pairId)
        {
            return _sources[pairId].Ticker;
        }

        public event Action<DateTime> Second;
        public DateTime CurrentTime { get; private set; }
        public Action PlaceOrder(int pairId, int quantity, Direction direction, Action<OrderFulfillmentResult> fullfilledAction, Action cancelledAction)
        {
            var ticker = GetTicker(pairId);
            var price = direction == Direction.Long ? ticker.Ask : ticker.Bid;
            if (price.HasValue)
            {
                fullfilledAction(new OrderFulfillmentResult(price.Value, ticker.Time, quantity));
            }
            else
            {
                cancelledAction();
            }
            return () => { };
        }
    }
}
