using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudApp.Services.Parsers;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel;
using Mapster;

namespace AsbCloudInfrastructure.Services.ExcelServices;

[Obsolete]
public abstract class ParserExcelService<TDto, TOptions> : IParserService<TDto, TOptions>
   where TDto : class, IValidatableObject, IId
   where TOptions : IParserOptionsRequest
{
   protected abstract ITemplateParameters TemplateParameters { get; }

   public virtual ParserResultDto<TDto> Parse(Stream file, TOptions options)
   {
      using var workbook = new XLWorkbook(file);
      var sheet = workbook.GetWorksheet(TemplateParameters.SheetName);
      var dtos = ParseExcelSheet(sheet);
      return dtos;
   }

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


   protected virtual IDictionary<string, object?> ParseRow(IXLRow xlRow)
   {
      var cells = TemplateParameters.Cells.ToDictionary(x => x.Key, x =>
      {
         var columnNumber = x.Value.ColumnNumber;
         var xlCell = xlRow.Cell(columnNumber);
         var cellValue = x.Value.GetValueFromCell(xlCell);
         return cellValue;
      });

      return cells;
   }

   protected virtual TDto BuildDto(IDictionary<string, object?> row, int rowNumber)
   {
      var dto = row.Adapt<TDto>();
      return dto;
   }

   private ValidationResultDto<TDto> Validate(TDto dto, int rowNumber)
   {
      var validationResults = new List<ValidationResult>();

      var isValid = dto.Validate(validationResults);

      if (isValid)
      {
         var validDto = new ValidationResultDto<TDto>
         {
            Item = dto
         };

         return validDto;
      }

      var columnsDict = TemplateParameters.Cells.ToDictionary(x => x.Key, x => x.Value.ColumnNumber);

      var invalidDto = new ValidationResultDto<TDto>
      {
         Item = dto,
         Warnings = validationResults
            .SelectMany(v => v.MemberNames
               .Where(columnsDict.ContainsKey)
               .Select(m =>
               {
                  var columnNumber = columnsDict[m];
                  var errorMessage = v.ErrorMessage;
                  var warningMessage = string.Format(XLExtentions.ProblemDetailsTemplate,
                     TemplateParameters.SheetName,
                     rowNumber,
                     columnNumber,
                     errorMessage);
                  var warning = new ValidationResult(warningMessage, new[] { m });
                  return warning;
               }))
      };

      return invalidDto;
   }

   protected virtual ParserResultDto<TDto> ParseExcelSheet(IXLWorksheet sheet)
   {
      var count = sheet.RowsUsed().Count() - TemplateParameters.HeaderRowsCount;
      if (count <= 0)
         return new ParserResultDto<TDto>();

      var valiationResults = new List<ValidationResultDto<TDto>>(count);
      var warnings = new List<ValidationResult>();

      for (var i = 0; i < count; i++)
      {
         var xlRow = sheet.Row(1 + i + TemplateParameters.HeaderRowsCount);
         var rowNumber = xlRow.RowNumber();

         try
         {
            var row = ParseRow(xlRow);
            var dto = BuildDto(row, rowNumber);
            var validationResult = Validate(dto, rowNumber);
            valiationResults.Add(validationResult);
         }
         catch (FileFormatException ex)
         {
            var warning = new ValidationResult(ex.Message);
            warnings.Add(warning);
         }
      }

      var parserResult = new ParserResultDto<TDto>
      {
         Item = valiationResults
      };

      if (warnings.Any())
         parserResult.Warnings = warnings;

      return parserResult;
   }
}