using Microsoft.AspNetCore.Components;

namespace Connected.Components;

partial class Line : Chart
{
	private const int MaxHorizontalGridLines = 100;

	[CascadingParameter] public Chart ChartParent { get; set; }

	private List<SvgPath> _horizontalLines = new();
	private List<SvgText> _horizontalValues = new();

	private List<SvgPath> _verticalLines = new();
	private List<SvgText> _verticalValues = new();

	private List<SvgLegend> _legends = new();
	private List<ChartSeries> _series = new();

	private List<SvgPath> _chartLines = new();

	protected override void OnParametersSet()
	{
		base.OnParametersSet();
		_horizontalLines.Clear();
		_verticalLines.Clear();
		_horizontalValues.Clear();
		_verticalValues.Clear();
		_legends.Clear();
		_chartLines.Clear();

		if (ChartParent != null)
			_series = ChartParent.ChartSeries;

		var maxY = 0.0;
		var numValues = 0;
		var numXLabels = XAxisLabels.Length;
		foreach (var item in _series)
		{
			if (numValues < item.Data.Length)
			{
				numValues = item.Data.Length;
			}
			foreach (int i in item.Data)
			{
				if (maxY < i)
				{
					maxY = i;
				}
			}
		}

		var boundHeight = 350.0;
		var boundWidth = 650.0;

		double gridYUnits = ChartParent?.ChartOptions.YAxisTicks ?? 20;
		if (gridYUnits <= 0)
			gridYUnits = 20;
		int maxYTicks = ChartParent?.ChartOptions.MaxNumYAxisTicks ?? 100;
		double gridXUnits = 30;

		var numVerticalLines = numValues - 1;

		var numHorizontalLines = ((int)(maxY / gridYUnits)) + 1;

		// this is a safeguard against millions of gridlines which might arise with very high values
		while (numHorizontalLines > maxYTicks)
		{
			gridYUnits *= 2;
			numHorizontalLines = ((int)(maxY / gridYUnits)) + 1;
		}

		var verticalStartSpace = 25.0;
		var horizontalStartSpace = 30.0;
		var verticalEndSpace = 25.0;
		var horizontalEndSpace = 30.0;

		var verticalSpace = (boundHeight - verticalStartSpace - verticalEndSpace) / (numHorizontalLines);
		var horizontalSpace = (boundWidth - horizontalStartSpace - horizontalEndSpace) / (numVerticalLines);
		var interpolationOption = ChartParent?.ChartOptions.InterpolationOption ?? InterpolationOption.Straight;

		//Horizontal Grid Lines
		var y = verticalStartSpace;
		double startGridY = 0;
		for (var counter = 0; counter <= numHorizontalLines; counter++)
		{
			var line = new SvgPath()
			{
				Index = counter,
				Data = $"M {ToS(horizontalStartSpace)} {ToS((boundHeight - y))} L {ToS((boundWidth - horizontalEndSpace))} {ToS((boundHeight - y))}"
			};
			_horizontalLines.Add(line);

			var lineValue = new SvgText() { X = (horizontalStartSpace - 10), Y = (boundHeight - y + 5), Value = ToS(startGridY, ChartParent?.ChartOptions.YAxisFormat) };
			_horizontalValues.Add(lineValue);

			startGridY += gridYUnits;
			y += verticalSpace;
		}

		//Vertical Grid Lines
		var x = horizontalStartSpace;
		double startGridX = 0;
		for (var counter = 0; counter <= numVerticalLines; counter++)
		{

			var line = new SvgPath()
			{
				Index = counter,
				Data = $"M {ToS(x)} {ToS((boundHeight - verticalStartSpace))} L {ToS(x)} {ToS(verticalEndSpace)}"
			};
			_verticalLines.Add(line);

			var xLabels = "";
			if (counter < numXLabels)
			{
				xLabels = XAxisLabels[counter];
			}

			var lineValue = new SvgText() { X = x, Y = boundHeight - 2, Value = xLabels };
			_verticalValues.Add(lineValue);

			startGridX += gridXUnits;
			x += horizontalSpace;
		}


		//Chart Lines
		var colorcounter = 0;
		foreach (var item in _series)
		{
			var chartLine = "";
			double gridValueX = 0;
			double gridValueY = 0;
			var firstTime = true;
			double[] XValues = new double[item.Data.Length];
			double[] YValues = new double[item.Data.Length];
			ILineInterpolator interpolator;
			for (var i = 0; i <= item.Data.Length - 1; i++)
			{
				if (i == 0)
					XValues[i] = 30;
				else
					XValues[i] = XValues[i - 1] + horizontalSpace;

				var gridValue = (item.Data[i]) * verticalSpace / gridYUnits;
				YValues[i] = boundHeight - (verticalStartSpace + gridValue);

			}
			switch (interpolationOption)
			{
				case InterpolationOption.NaturalSpline:
					interpolator = new NaturalSpline(XValues, YValues);
					break;
				case InterpolationOption.EndSlope:
					interpolator = new EndSlopeSpline(XValues, YValues);
					break;
				case InterpolationOption.Periodic:
					interpolator = new PeriodicSpline(XValues, YValues);
					break;
				case InterpolationOption.Straight:
				default:
					interpolator = new NoInterpolation();
					break;
			}

			if (interpolator?.InterpolationRequired == true)
			{
				horizontalSpace = (boundWidth - horizontalStartSpace - horizontalEndSpace) / interpolator.InterpolatedXs.Length;
				foreach (var yValue in interpolator.InterpolatedYs)
				{

					if (firstTime)
					{

						chartLine += "M ";
						firstTime = false;
						gridValueX = horizontalStartSpace;
						gridValueY = verticalStartSpace;
					}
					else
					{
						chartLine += " L ";
						gridValueX += horizontalSpace;
						gridValueY = verticalStartSpace;
					}
					gridValueY = yValue;
					chartLine = chartLine + ToS(gridValueX) + " " + ToS(gridValueY);
				}
			}
			else
			{
				foreach (var dataLine in item.Data)
				{
					if (firstTime)
					{
						chartLine += "M ";
						firstTime = false;
						gridValueX = horizontalStartSpace;
						gridValueY = verticalStartSpace;
					}
					else
					{
						chartLine += " L ";
						gridValueX += horizontalSpace;
						gridValueY = verticalStartSpace;
					}

					var gridValue = ((double)dataLine) * verticalSpace / gridYUnits;
					gridValueY = boundHeight - (gridValueY + gridValue);
					chartLine = chartLine + ToS(gridValueX) + " " + ToS(gridValueY);
				}
			}

			var line = new SvgPath()
			{
				Index = colorcounter,
				Data = chartLine
			};

			var legend = new SvgLegend()
			{
				Index = colorcounter,
				Labels = item.Name
			};
			colorcounter++;
			_chartLines.Add(line);
			_legends.Add(legend);
		}
	}
}
