using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
using ClosedXML.Excel;

namespace AsbCloudInfrastructure.Services.WellOperationImport;

public class WellOperationExportService : IWellOperationExportService
{
	//TODO: удалить неиспользуемую зависимость
	private readonly IWellOperationRepository wellOperationRepository;
	private readonly IWellService wellService;
	private readonly IWellOperationImportTemplateService wellOperationImportTemplateService;

	public WellOperationExportService(IWellOperationRepository wellOperationRepository,
		IWellService wellService,
		IWellOperationImportTemplateService wellOperationImportTemplateService)
	{
		this.wellOperationRepository = wellOperationRepository;
		this.wellService = wellService;
		this.wellOperationImportTemplateService = wellOperationImportTemplateService;
	}

	public async Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken)
	{
		var operations = await wellOperationRepository.GetAsync(new WellOperationRequest()
		{
			IdWell = idWell
		}, cancellationToken);

		return MakeExcelFileStream(operations);
	}

	private Stream MakeExcelFileStream(IEnumerable<WellOperationDto> operations)
	{
		using Stream ecxelTemplateStream = wellOperationImportTemplateService.GetExcelTemplateStream();

		using var workbook = new XLWorkbook(ecxelTemplateStream);
		AddOperationsToWorkbook(workbook, operations);

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

	private void AddOperationsToWorkbook(XLWorkbook workbook, IEnumerable<WellOperationDto> operations)
	{
		var planOperations = operations.Where(o => o.IdType == 0);
		if (planOperations.Any())
		{
			var sheetPlan = workbook.GetWorksheet(DefaultTemplateInfo.SheetNamePlan);
			
			AddOperationsToSheet(sheetPlan, planOperations);
		}

		var factOperations = operations.Where(o => o.IdType == 1);
		if (factOperations.Any())
		{
			var sheetFact = workbook.GetWorksheet(DefaultTemplateInfo.SheetNameFact);
			
			AddOperationsToSheet(sheetFact, factOperations);
		}
	}

	private void AddOperationsToSheet(IXLWorksheet sheet, IEnumerable<WellOperationDto> operations)
	{
		var operationsToArray = operations.ToArray();

		var sections = wellOperationRepository.GetSectionTypes();
		var categories = wellOperationRepository.GetCategories(false);

		for (int i = 0; i < operationsToArray.Length; i++)
		{
			var row = sheet.Row(1 + i + DefaultTemplateInfo.HeaderRowsCount);
			AddOperationToRow(row, operationsToArray[i], sections, categories);
		}
	}

	private static void AddOperationToRow(IXLRow row, WellOperationDto operation, IEnumerable<WellSectionTypeDto> sections,
		IEnumerable<WellOperationCategoryDto> categories)
	{
		var sectionCaption = sections.First(s => s.Id == operation.IdWellSectionType).Caption;
		var categoryName = categories.First(o => o.Id == operation.IdCategory).Name;
		
		row.Cell(DefaultTemplateInfo.ColumnSection).SetCellValue(sectionCaption);
		row.Cell(DefaultTemplateInfo.ColumnCategory).SetCellValue(categoryName);
		row.Cell(DefaultTemplateInfo.ColumnCategoryInfo).SetCellValue(operation.CategoryInfo);
		row.Cell(DefaultTemplateInfo.ColumnDepthStart).SetCellValue(operation.DepthStart);
		row.Cell(DefaultTemplateInfo.ColumnDepthEnd).SetCellValue(operation.DepthEnd);
		row.Cell(DefaultTemplateInfo.ColumnDate).SetCellValue(operation.DateStart.DateTime);
		row.Cell(DefaultTemplateInfo.ColumnDuration).SetCellValue(operation.DurationHours);
		row.Cell(DefaultTemplateInfo.ColumnComment).SetCellValue(operation.Comment);
	}
}