using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperationImport;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services.WellOperationImport;

namespace AsbCloudInfrastructure.Services.WellOperationImport;

public class WellOperationImportService : IWellOperationImportService
{
	private readonly IWellOperationRepository wellOperationRepository;

	private static readonly DateTime dateLimitMin = new(2001, 1, 1, 0, 0, 0);
	private static readonly DateTime dateLimitMax = new(2099, 1, 1, 0, 0, 0);
	private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);

	public WellOperationImportService(IWellOperationRepository wellOperationRepository)
	{
		this.wellOperationRepository = wellOperationRepository;
	}

	public IEnumerable<WellOperationDto> Import(int idWell, int idUser, int idType, SheetDto sheet)
	{
		var validationErrors = new List<string>();

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

		var wellOperations = new List<WellOperationDto>();

		foreach (var row in sheet.Rows)
		{
			try
			{
				var section = sections.FirstOrDefault(s =>
					string.Equals(s.Caption, row.Section, StringComparison.CurrentCultureIgnoreCase));

				if (section is null)
					throw new FileFormatException($"Лист '{sheet.Name}'. В строке '{row.Number}' не удалось определить секцию");

				var category = categories.FirstOrDefault(c =>
					string.Equals(c.Name, row.Category, StringComparison.CurrentCultureIgnoreCase));

				if (category is null)
					throw new FileFormatException($"Лист '{sheet.Name}'. В строке '{row.Number}' не удалось определить операцию");

				if (row.DepthStart is not (>= 0d and <= 20_000d))
					throw new FileFormatException(
						$"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная глубина на начало операции");

				if (row.DepthEnd is not (>= 0d and <= 20_000d))
					throw new FileFormatException(
						$"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная глубина на конец операции");

				if (row.Date < dateLimitMin && row.Date > dateLimitMax)
					throw new FileFormatException(
						$"Лист '{sheet.Name}'. Строка '{row.Number}' неправильно получена дата начала операции");

				if (wellOperations.LastOrDefault()?.DateStart > row.Date)
					throw new FileFormatException(
						$"Лист '{sheet.Name}' строка '{row.Number}' дата позднее даты предыдущей операции");

				if (row.Duration is not (>= 0d and <= 240d))
					throw new FileFormatException($"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная длительность операции");

				wellOperations.Add(new WellOperationDto
				{
					IdWell = idWell,
					IdUser = idUser,
					IdType = idType,
					IdWellSectionType = section.Id,
					IdCategory = category.Id,
					CategoryInfo = row.CategoryInfo,
					DepthStart = row.DepthStart,
					DepthEnd = row.DepthEnd,
					DateStart = row.Date,
					DurationHours = row.Duration
				});
			}
			catch (FileFormatException ex)
			{
				validationErrors.Add(ex.Message);
			}
		}

		if (wellOperations.Any() && wellOperations.Min(o => o.DateStart) - wellOperations.Max(o => o.DateStart) > drillingDurationLimitMax)
			validationErrors.Add($"Лист {sheet.Name} содержит диапазон дат больше {drillingDurationLimitMax}");

		if (validationErrors.Any())
			throw new FileFormatException(string.Join("\r\n", validationErrors));
		
		return wellOperations;
	}
}