using System;
using System.IO;
using AsbCloudInfrastructure;
using ClosedXML.Excel;
using Xunit;

namespace AsbCloudWebApi.Tests;

public class XLExtensionsTests
{
	private const string cellUsed = "A1";
	private const string sheetName = "test";

	private readonly IXLWorkbook workbook;

	public XLExtensionsTests()
	{
		workbook = new XLWorkbook();
		workbook.Worksheets.Add(sheetName);
	}

	[Fact]
	public void GetWorksheet_returns_sheet()
	{
		//act
		var sheet = workbook.GetWorksheet(sheetName);

		//assert
		Assert.NotNull(sheet);
	}

	[Theory]
	[MemberData(nameof(valueTypesToSet))]
	public void SetCellValue_returns_success(object value, XLDataType expectedDataType)
	{
		//act
		var cell = GetCell(cellUsed);
		cell.SetCellValue(value);

		//assert
		Assert.Equal(expectedDataType, cell.DataType);
	}
	
	[Fact]
	public void GetCellValue_returns_double()
	{
		//arrange
		const double expectedValue = 2.0d;
		SetCellValue(expectedValue);

		//act
		var actualValue = GetCell(cellUsed).GetCellValue<double>();
		
		//assert
		Assert.Equal(expectedValue, actualValue);
	}

	[Fact]
	public void GetCellValue_returns_float()
	{
		//arrange
		const float expectedValue = 2.0f;
		SetCellValue(expectedValue);
		
		//act
		var actualValue = GetCell(cellUsed).GetCellValue<float>();
		
		//assert
		Assert.Equal(expectedValue, actualValue);
	}

	[Theory]
	[InlineData("test")]
	[InlineData(null)]
	public void GetCellValue_returns_string(string? expectedValue)
	{
		//arrange
		SetCellValue(expectedValue);
		
		//act
		var actualValue = GetCell(cellUsed).GetCellValue<string>();
		
		//assert
		Assert.Equal(expectedValue, actualValue);
	}

	[Fact]
	public void GetCellValue_returns_bool()
	{
		//arrange
		const bool expectedValue = true;
		SetCellValue(expectedValue);
		
		//act
		var actualValue = GetCell(cellUsed).GetCellValue<bool>();
		
		//assert
		Assert.Equal(expectedValue, actualValue);
	}

	[Fact]
	public void GetCellValue_returns_dateTime()
	{
		//arrange
		var expectedValue = DateTime.Parse("2023-01-01");
		SetCellValue(expectedValue);
		
		//act
		var actualValue = GetCell(cellUsed).GetCellValue<DateTime>();
		
		//assert
		Assert.Equal(expectedValue, actualValue);
		Assert.Equal(DateTimeKind.Unspecified, actualValue.Kind);
	}

	[Fact]
	public void GetCellValue_returns_exception()
	{
		//arrange
		SetCellValue("test");

		//assert
		Assert.Throws<FileFormatException>(() => GetCell(cellUsed).GetCellValue<double>());
	}

	[Fact]
	public void GetCellValue_returns_nullable()
	{
		//act
		var actualValue = GetCell(cellUsed).GetCellValue<object?>();
		
		//assert
		Assert.Null(actualValue);
	}

	[Fact]
	public void SetHyperlink_returns_success()
	{
		//arrange
		const string link = "http://test.ru";
		
		//act
		GetCell(cellUsed).SetHyperlink(link);
		
		//assert
		var hyperLink = GetCell(cellUsed).GetHyperlink();
		Assert.NotNull(hyperLink);
	}

	private void SetCellValue<T>(T value)
	{
		var cell = GetCell(cellUsed);
		cell.SetCellValue(value);
	}

	public static readonly object[][] valueTypesToSet =
	{
		new object[] { 2.0d, XLDataType.Number },
		new object[] { 2.0f, XLDataType.Number },
		new object[] { "test", XLDataType.Text },
		new object[] { true, XLDataType.Boolean },
		new object[] { DateTime.UtcNow, XLDataType.DateTime }
	};

	private IXLCell GetCell(string cellAddressInRange)
	{
		var sheet = workbook.GetWorksheet(sheetName);
		return sheet.Cell(cellAddressInRange);
	}
}