using AsbCloudApp.Data;
using ClosedXML.Excel;
using System;
using System.IO;
using System.Linq;

namespace AsbCloudInfrastructure.Services.DailyReport
{
    public class DailyReportMakerExcel
    {
        public Stream MakeReport(DailyReportDto dailyReportDto)
        {
            using var templateStream = System.Reflection.Assembly.GetExecutingAssembly()
                .GetManifestResourceStream("AsbCloudInfrastructure.Services.DailyReport.DailyReportTemplate.xlsx");
            using var workbook = new XLWorkbook(templateStream, XLEventTracking.Disabled);
            FillSheet(workbook, dailyReportDto);

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

        public void FillSheet(XLWorkbook workbook, DailyReportDto reportParams)
        {
            var sheet = workbook.Worksheets.First();//.Add(reportParams.ReportDate.ToString("dd.MM.yyyy"));
            sheet.Name = reportParams.ReportDate.ToString("dd.MM.yyyy");

            var activeRow = 3;
            activeRow = AddBlockHead(sheet, activeRow, reportParams);
            activeRow = AddBlockSlaughtersReport(sheet, activeRow, reportParams);
            activeRow = AddBlockTrajectoryReport(sheet, activeRow, reportParams);
            activeRow = AddBlockDrillers(sheet, activeRow, reportParams);
            activeRow = AddBlockSAUB(sheet, activeRow, reportParams);
            activeRow = AddBlockBHA(sheet, activeRow, reportParams);
            activeRow = AddBlockBHADescription(sheet, activeRow, reportParams);
            activeRow = AddBlockOperations(sheet, activeRow, reportParams);
            activeRow = AddBlockTimeBalans(sheet, activeRow, reportParams);
            activeRow = AddBlockMeterlessWorks(sheet, activeRow, reportParams);
            activeRow = AddBlockDrillingModes(sheet, activeRow, reportParams);
            activeRow = AddBlockRotorDrilling(sheet, activeRow, reportParams);
            activeRow = AddBlockSlideDrilling(sheet, activeRow, reportParams);
            activeRow = AddBlockROPPlan(sheet, activeRow, reportParams);
            activeRow = AddBlockSummary(sheet, activeRow, reportParams);
            activeRow = AddBlockSubscribes(sheet, activeRow, reportParams);
        }

        private int AddBlockHead(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow, 3).Value =
                $"Суточная сводка бурения скважины №{reportDto.WellName}, куст: {reportDto.ClusterName}";
            sheet.Cell(startRow + 1, 3).Value =
                $"Заказчик: {reportDto.Customer}";
            sheet.Cell(startRow + 2, 3).Value =
                $"Подрядчик: {reportDto.Contractor}";

            return startRow + 2;
        }

        private int AddBlockSlaughtersReport(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 4, 3).Value =
                $"{reportDto.ReportDate}";
            sheet.Cell(startRow + 4, 5).Value =
                $"{reportDto.WellDepthIntervalStartDate}";
            sheet.Cell(startRow + 4, 6).Value =
                $"{reportDto.WellDepthIntervalFinishDate}";

            return startRow + 4;
        }

        private int AddBlockTrajectoryReport(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 4, 3).Value =
                $"{reportDto.BottomholeDepth}";
            sheet.Cell(startRow + 4, 4).Value =
                $"{reportDto.VerticalDepth}";
            sheet.Cell(startRow + 4, 5).Value =
                $"{reportDto.ZenithAngle}";
            sheet.Cell(startRow + 4, 6).Value =
                $"{reportDto.AzimuthAngle}";

            return startRow + 4;
        }

        private int AddBlockDrillers(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 2, 4).Value =
                $"{reportDto.FirstDriller}";
            sheet.Cell(startRow + 3, 4).Value =
                $"{reportDto.SecondDriller}";

            return startRow + 3;
        }

        private int AddBlockSAUB(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 3, 6).Value =
                $"{reportDto.WorkTimeSAUB}";
            sheet.Cell(startRow + 4, 6).Value =
                $"{reportDto.WorkTimeSpinMaster}";
            sheet.Cell(startRow + 5, 6).Value =
                $"{reportDto.WorkTimeTorkMaster}";
            sheet.Cell(startRow + 3, 7).Value =
                $"{reportDto.PenetrationSAUB}";
            sheet.Cell(startRow + 4, 7).Value =
                $"{reportDto.PenetrationSpinMaster}";
            sheet.Cell(startRow + 5, 7).Value =
                $"{reportDto.PenetrationTorkMaster}";
            sheet.Cell(startRow + 6, 6).Value =
                 $"{reportDto.CountLaunchesMSE}";

            return startRow + 6;
        }

        private int AddBlockBHA(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 3, 6).Value =
                $"{reportDto.WorkTimeSAUB}";
            sheet.Cell(startRow + 4, 6).Value =
                $"{reportDto.WorkTimeSpinMaster}";
            sheet.Cell(startRow + 5, 6).Value =
                $"{reportDto.WorkTimeTorkMaster}";
            sheet.Cell(startRow + 3, 7).Value =
                $"{reportDto.PenetrationSAUB}";
            sheet.Cell(startRow + 4, 7).Value =
                $"{reportDto.PenetrationSpinMaster}";
            sheet.Cell(startRow + 5, 7).Value =
                $"{reportDto.PenetrationTorkMaster}";
            sheet.Cell(startRow + 6, 6).Value =
                 $"{reportDto.CountLaunchesMSE}";

            return startRow + 6;
        }

        private int AddBlockBHADescription(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 2, 3).Value =
                $"{reportDto.BHADescription}";

            return startRow + 6;
        }

        private int AddBlockOperations(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            return startRow + 7;
        }

        private int AddBlockTimeBalans(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            return startRow + 8;
        }

        private int AddBlockMeterlessWorks(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 4, 6).Value =
                $"{reportDto.StandardTimeBarrelPreparation}";
            sheet.Cell(startRow + 4, 9).Value =
                $"{reportDto.StandardTimeExtension}";
            sheet.Cell(startRow + 6, 6).Value =
                $"{reportDto.ActualTimeBarrelPreparation}";
            sheet.Cell(startRow + 6, 9).Value =
                $"{reportDto.ActualTimeExtension}";

            return startRow + 9;
        }

        private int AddBlockDrillingModes(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 2, 6).Value =
                $"{string.Join(", ", reportDto.RotorDrillingModes)}";
            sheet.Cell(startRow + 3, 9).Value =
                $"{string.Join(", ", reportDto.SlideDrillingModes)}";

            return startRow + 3;
        }

        private int AddBlockRotorDrilling(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 3, 3).Value =
                $"{reportDto.PenetrationInRotor}";
            sheet.Cell(startRow + 3, 5).Value =
                $"{reportDto.NumberDrillingHours}";
            sheet.Cell(startRow + 3, 9).Value =
                $"{reportDto.AVGDiffDropRotor}";

            return startRow + 3;
        }

        private int AddBlockSlideDrilling(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 3, 3).Value =
                $"{reportDto.PenetrationInSlide}";
            sheet.Cell(startRow + 3, 5).Value =
                $"{reportDto.DrillingTimeInRotor}";
            sheet.Cell(startRow + 3, 9).Value =
                $"{reportDto.AVGDiffPressureSlide}";

            return startRow + 3;
        }

        private int AddBlockROPPlan(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 3, 9).Value =
                $"{reportDto.SectionROPPlan}";

            return startRow + 3;
        }

        private int AddBlockSummary(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 7, 7).Value =
                $"{reportDto.SectionDrillingTimeTotal}";
            sheet.Cell(startRow + 8, 7).Value =
                $"{reportDto.SectionPenetrationTotal}";
            sheet.Cell(startRow + 9, 7).Value =
                $"{reportDto.ExtensionsCount}";
            sheet.Cell(startRow + 10, 7).Value =
                $"{reportDto.DeviationFromTVD}";
            sheet.Cell(startRow + 11, 3).Value =
                $"{reportDto.DeclinesReasonsROP}";

            return startRow + 13;
        }
        private int AddBlockSubscribes(IXLWorksheet sheet, int startRow, DailyReportDto reportDto)
        {
            sheet.Cell(startRow + 3, 9).Value =
                $"{reportDto.DrillingMaster}";
            sheet.Cell(startRow + 5, 9).Value =
                $"{reportDto.Supervisor}";

            return startRow + 5;
        }

        private static string GetColunmLetter(int columnNumber)
        {
            string letter = "";

            while (columnNumber > 0)
            {
                int modulo = (columnNumber - 1) % 26;
                letter = Convert.ToChar('A' + modulo) + letter;
                columnNumber = (columnNumber - modulo) / 26;
            }

            return letter;
        }

        private static IXLStyle SetBorder(IXLStyle style)
        {
            style.Border.RightBorder = XLBorderStyleValues.Thin;
            style.Border.LeftBorder = XLBorderStyleValues.Thin;
            style.Border.TopBorder = XLBorderStyleValues.Thin;
            style.Border.BottomBorder = XLBorderStyleValues.Thin;
            style.Border.InsideBorder = XLBorderStyleValues.Thin;
            return style;
        }

        private static IXLCell SetDateTime(IXLCell cell)
        {
            cell.DataType = XLDataType.DateTime;
            cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS";
            return cell;
        }

        private static IXLCell SetNumber(IXLCell cell)
        {
            cell.DataType = XLDataType.Number;
            cell.Style.NumberFormat.Format = "0.00";
            return cell;
        }

        private static IXLCell SetCell(IXLRow row, int colunm, object value, int maxChartsToWrap = 88)
        {
            var cell = row.Cell(colunm);
            cell.Value = value;

            SetBorder(cell.Style);
            cell.Style.Alignment.WrapText = true;

            if (value is string valueString && valueString.Length > maxChartsToWrap)
            {
                var baseHeight = row.Height;
                row.Height = 0.82d * baseHeight * Math.Ceiling(1d + valueString.Length / maxChartsToWrap);
            }

            if (value is DateTime)
            {
                SetDateTime(cell);
            }
            else if (value is IFormattable)
            {
                SetNumber(cell);
            }

            return cell;
        }
    }
}