using AsbCloudApp.Data.Trajectory;
using ClosedXML.Excel;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace AsbCloudInfrastructure.Services.Trajectory.Import
{
    public abstract class TrajectoryParserService<T>
        where T : TrajectoryGeoDto
    {
        public abstract string templateFileName { get; }
        public abstract string usingTemplateFile { get; }
        public abstract string sheetName { get; }
        public abstract int headerRowsCount { get; }

        protected abstract T ParseRow(IXLRow row);

        public IEnumerable<T> Import(Stream stream)
        {
            using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
            var trajectoryRows = ParseFileStream(stream);

            return trajectoryRows;
        }


        private IEnumerable<T> ParseFileStream(Stream stream)
        {
            using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
            return ParseWorkbook(workbook);
        }

        private IEnumerable<T> ParseWorkbook(IXLWorkbook workbook)
        {
            var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName);
            if (sheetTrajectory is null)
                throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
            var trajectoryRows = ParseSheet(sheetTrajectory);
            return trajectoryRows;
        }

        private IEnumerable<T> ParseSheet(IXLWorksheet sheet)
        {
            if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 6)
                throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");

            var count = sheet.RowsUsed().Count() - headerRowsCount;

            if (count > 1024)
                throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");

            if (count <= 0)
                throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой");

            var trajectoryRows = new List<T>(count);
            var parseErrors = new List<string>();
            for (int i = 0; i < count; i++)
            {
                var row = sheet.Row(1 + i + headerRowsCount);
                try
                {
                    var trajectoryRow = ParseRow(row);
                    trajectoryRows.Add(trajectoryRow);
                }
                catch (FileFormatException ex)
                {
                    parseErrors.Add(ex.Message);
                }
            }

            if (parseErrors.Any())
                throw new FileFormatException(string.Join("\r\n", parseErrors));

            return trajectoryRows;
        }
    }
}