using System;
using System.Collections.Generic;
using System.IO;
using ClosedXML.Excel;

namespace AsbCloudInfrastructure.Services.ExcelServices;

public class Cell
{
	private static IDictionary<Type, Func<IXLCell, object?>> converters = new Dictionary<Type, Func<IXLCell, object?>>()
	{
		{ typeof(bool), cell => cell.GetBoolean() },
		{ typeof(double), cell => cell.GetValue<double>() },
		{ typeof(float), cell => cell.GetValue<float>() },
		{ typeof(long), cell => cell.GetValue<long>() },
		{ typeof(ulong), cell => cell.GetValue<ulong>() },
		{ typeof(int), cell => cell.GetValue<int>() },
		{ typeof(uint), cell => cell.GetValue<uint>() },
		{ typeof(short), cell => cell.GetValue<short>() },
		{ typeof(ushort), cell => cell.GetValue<ushort>() },
		{ typeof(string), cell => cell.GetString() },

		{
			typeof(DateTime), cell =>
			{
				if (cell.DataType == XLDataType.DateTime)
					return cell.GetDateTime();

				var stringValue = cell.GetString();
				return DateTime.Parse(stringValue);
			}
		},

		{
			typeof(DateTimeOffset), cell =>
			{
				var stringValue = cell.GetString();
				return DateTimeOffset.Parse(stringValue);
			}
		},

		{
			typeof(DateOnly), cell =>
			{
				var stringValue = cell.GetString();
				return DateOnly.Parse(stringValue);
			}
		},

		{
			typeof(TimeOnly), cell =>
			{
				var stringValue = cell.GetString();
				return TimeOnly.Parse(stringValue);
			}
		},

		{
			typeof(TimeSpan), cell =>
			{
				if (cell.DataType == XLDataType.TimeSpan)
					return cell.GetTimeSpan();

				var stringValue = cell.GetString();
				return TimeSpan.Parse(stringValue);
			}
		},
	};

	private readonly Type type;

	public Cell(int columnNumber,
		Type type)
	{
		ColumnNumber = columnNumber;
		this.type = type;
	}

	public int ColumnNumber { get; }

	public object? GetValueFromCell(IXLCell cell)
	{
		try
		{
			return converters[type].Invoke(cell);
		}
		catch
		{
			var message = string.Format(XLExtentions.InvalidValueTemplate, cell.Worksheet.Name, cell.Address.RowNumber,
				cell.Address.ColumnNumber);
			throw new FileFormatException(message);
		}
	}
}