using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests.ExportOptions;
using AsbCloudApp.Services.Export;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel;
using Mapster;

namespace AsbCloudInfrastructure.Services.ExcelServices;

[Obsolete]
public abstract class ExportExcelService<TDto, TOptions> : IExportService<TOptions>
	where TOptions : IExportOptionsRequest
{
	protected abstract ITemplateParameters TemplateParameters { get; }

	protected abstract Task<string> BuildFileNameAsync(TOptions options, CancellationToken token);

	protected abstract Task<IEnumerable<TDto>> GetDtosAsync(TOptions options, CancellationToken token);

	public async Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token)
	{
		var dtos = await GetDtosAsync(options, token);

		var fileName = await BuildFileNameAsync(options, token);
		var file = BuildFile(dtos);
		return (fileName, file);
	}

	private Stream BuildFile(IEnumerable<TDto> dtos)
	{
		using var template = GetTemplateFile();
		using var workbook = new XLWorkbook(template);
		AddDtosToWorkbook(workbook, dtos);

		var memoryStream = new MemoryStream();
		workbook.SaveAs(memoryStream, new SaveOptions { });
		memoryStream.Seek(0, SeekOrigin.Begin);
		return memoryStream;
	}

	private void AddDtosToWorkbook(XLWorkbook workbook, IEnumerable<TDto> dtos)
	{
		var dtosToArray = dtos.ToArray();

		if (!dtosToArray.Any())
			return;

		var sheet = workbook.GetWorksheet(TemplateParameters.SheetName);
		for (var i = 0; i < dtosToArray.Length; i++)
		{
			var row = sheet.Row(1 + i + TemplateParameters.HeaderRowsCount);
			AddRow(row, dtosToArray[i]);
		}
	}

	private void AddRow(IXLRow xlRow, TDto dto)
	{
		var properties = dto.Adapt<IDictionary<string, object>>();

		foreach (var (name, cellValue) in properties)
		{
			if (TemplateParameters.Cells.TryGetValue(name, out var cell))
				xlRow.Cell(cell.ColumnNumber).SetCellValue(cellValue);
		}
	}

	private Stream GetTemplateFile() =>
		Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateParameters.FileName)
		?? throw new ArgumentNullException($"Файл '{TemplateParameters.FileName}' не найден");
}