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);
      }
   }
}