﻿using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Threading.Tasks;

namespace Cassini.MBTA.Core
{
	public static class Schedules
	{
		public static SchedulesByStop ByStop (string stopCode, string routeCode = null, int? direction = null,
			DateTime? afterTime = null, int? scheduleWindow = null, int? maxTrips = null, string apiKey = null)
		{
			return ByStopAsync (stopCode, routeCode, direction, afterTime, scheduleWindow, maxTrips).Result;
		}

		public async static Task<SchedulesByStop> ByStopAsync (string stopCode, string routeCode = null,
			int? direction = null, DateTime? afterTime = null,
			int? scheduleWindow = null, int? maxTrips = null, string apiKey = null)
		{
			if (stopCode == null)
				throw new ArgumentNullException ("stopCode");
			var arguments =  createdArgs (stopCode, routeCode, null, direction, afterTime, scheduleWindow, maxTrips);
			var url = string.Format (stopURL, apiKey ?? Consts.APIKey, arguments);
			var response = await WebUtils.GetData (url);

			return JsonConvert.DeserializeObject<SchedulesByStop>(response);
		}

		readonly static string stopURL =
			"http://realtime.mbta.com/developer/api/v2/schedulebystop?api_key={0}&{1}&format=json";

		public static ScheduleRoute ByRoute (string routeCode = null,
			int? direction = null, DateTime? afterTime = null,
			int? scheduleWindow = null, int? maxTrips = null, string apiKey = null)
		{
			return ByRouteAsync (routeCode, direction, afterTime, scheduleWindow, maxTrips, apiKey).Result;
		}

		public async static Task<ScheduleRoute> ByRouteAsync (string routeCode,
			int? direction = null, DateTime? afterTime = null,
			int? scheduleWindow = null, int? maxTrips = null, string apiKey = null)
		{
			if (routeCode == null)
				throw new ArgumentNullException ("routeCode");
			var arguments =  createdArgs (null, routeCode, null, direction, afterTime, scheduleWindow, maxTrips);
			var url = string.Format (routesURL, apiKey ?? Consts.APIKey, arguments);
			var response = await WebUtils.GetData (url);

			return JsonConvert.DeserializeObject<ScheduleRoute>(response);
		}

		readonly static string routesURL =
			"http://realtime.mbta.com/developer/api/v2/schedulebyroute?api_key={0}&{1}&format=json";

		public static ScheduleTrip ByTrip (string tripId,
			DateTime? afterTime = null, string apiKey = null)
		{
			return ByTripAsync (tripId, afterTime, apiKey).Result;
		}

		public async static Task<ScheduleTrip> ByTripAsync (string tripId,
			 DateTime? afterTime = null, string apiKey = null)
		{
			if (tripId == null)
				throw new ArgumentNullException ("tripId");
			var arguments =  createdArgs (null, null, tripId, null, afterTime, null, null);
			var url = string.Format (tripURL, apiKey ?? Consts.APIKey, arguments);
			var response = await WebUtils.GetData (url);

			return JsonConvert.DeserializeObject<ScheduleTrip>(response);
		}

		readonly static string tripURL =
			"http://realtime.mbta.com/developer/api/v2/schedulebytrip?api_key={0}&{1}&format=json";

		static string createdArgs (string stopCode, string routeCode, string tripId, int? direction,
			DateTime? afterTime, int? scheduleWindow, int? maxTrips)
		{
			var urlSection = new List<string> ();
			if (!string.IsNullOrEmpty (stopCode))
				urlSection.Add (string.Format ("stop={0}", stopCode));
			if (!string.IsNullOrEmpty (routeCode))
				urlSection.Add (string.Format ("route={0}", routeCode));
			if (!string.IsNullOrEmpty (tripId))
				urlSection.Add (string.Format ("trip={0}", tripId));
			if (direction != null) {
				if (direction.Value == 0 || direction.Value == 1)
					urlSection.Add (string.Format ("direction={0}", direction.Value));
				else
					throw new ArgumentException ("Argument 'direction' cannot be null", "direction");
			}
			if (afterTime != null) {
				var mbtaTime = Server.GetTime ();
				var timeDiff = afterTime.Value - mbtaTime.DateTime;
				if (timeDiff < new TimeSpan (7, 0, 0, 0))
					urlSection.Add (string.Format ("datetime={0}", (int)timeDiff.TotalMinutes));
				else
					throw new ArgumentException ("Argument 'afterTime' needs to be within 7 days of Eastern Time",
						"afterTime");
			}
			if (scheduleWindow != null) {
				if (scheduleWindow.Value >= 1 || scheduleWindow.Value <= 1440)
					urlSection.Add (string.Format ("max_time={0}", scheduleWindow.Value));
				else
					throw new ArgumentException ("Argument 'scheduleWindow' needs to be between 1 and 1440",
						"scheduleWindow");
			}
			if (maxTrips != null) {
				if (maxTrips.Value >= 1 || maxTrips.Value <= 100)
					urlSection.Add (string.Format ("max_trips={0}", maxTrips.Value));
				else
					throw new ArgumentException ("Argument 'maxTrips' needs to be between 1 and 100",
						"maxTrips");
			}

			return string.Join ("&", urlSection);
		}
	}
}

