using BarBusinessLogic.OfficePackage.HelperEnums;
using BarBusinessLogic.OfficePackage.HelperModels;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Office2010.Excel;
using DocumentFormat.OpenXml.Office2013.Excel;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

namespace BarBusinessLogic.OfficePackage.Implements
{
    public class SaveToExcel : AbstractSaveToExcel
    {
        private SpreadsheetDocument? _spreadsheetDocument;
        private SharedStringTablePart? _shareStringPart;
        private Worksheet? _worksheet;

        private static void CreateStyles(WorkbookPart WorkbookPart)
        {
            var sp = WorkbookPart.AddNewPart<WorkbookStylesPart>();
            sp.Stylesheet = new Stylesheet();

            var Fonts = new Fonts() { Count = 2U, KnownFonts = true };

            var FontUsual = new Font();
            FontUsual.Append(new FontSize() { Val = 12D });
            FontUsual.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Theme = 1U });
            FontUsual.Append(new FontName() { Val = "Times New Roman" });
            FontUsual.Append(new FontFamilyNumbering() { Val = 2 });
            FontUsual.Append(new FontScheme() { Val = FontSchemeValues.Minor });

            var FontTitle = new Font();
            FontTitle.Append(new Bold());
            FontTitle.Append(new FontSize() { Val = 14D });
            FontTitle.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Theme = 1U });
            FontTitle.Append(new FontName() { Val = "Times New Roman" });
            FontTitle.Append(new FontFamilyNumbering() { Val = 2 });
            FontTitle.Append(new FontScheme() { Val = FontSchemeValues.Minor });

            Fonts.Append(FontUsual);
            Fonts.Append(FontTitle);

            var Fills = new Fills() { Count = 2U };

            var Fill1 = new Fill();
            Fill1.Append(new PatternFill() { PatternType = PatternValues.None });

            var Fill2 = new Fill();
            Fill2.Append(new PatternFill() { PatternType = PatternValues.Gray125 });

            Fills.Append(Fill1);
            Fills.Append(Fill2);

            var Borders = new Borders() { Count = 2U };

            var BorderNoBorder = new Border();
            BorderNoBorder.Append(new LeftBorder());
            BorderNoBorder.Append(new RightBorder());
            BorderNoBorder.Append(new TopBorder());
            BorderNoBorder.Append(new BottomBorder());
            BorderNoBorder.Append(new DiagonalBorder());

            var BorderThin = new Border();

            var LeftBorder = new LeftBorder() { Style = BorderStyleValues.Thin };
            LeftBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });

            var RightBorder = new RightBorder() { Style = BorderStyleValues.Thin };
            RightBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });

            var TopBorder = new TopBorder() { Style = BorderStyleValues.Thin };
            TopBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });

            var BottomBorder = new BottomBorder() { Style = BorderStyleValues.Thin };
            BottomBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });

            BorderThin.Append(LeftBorder);
            BorderThin.Append(RightBorder);
            BorderThin.Append(TopBorder);
            BorderThin.Append(BottomBorder);
            BorderThin.Append(new DiagonalBorder());

            Borders.Append(BorderNoBorder);
            Borders.Append(BorderThin);

            var CellStyleFormats = new CellStyleFormats() { Count = 1U };
            var CellFormatStyle = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 0U };

            CellStyleFormats.Append(CellFormatStyle);

            var CellFormats = new CellFormats() { Count = 3U };
            var CellFormatFont = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 0U, FormatId = 0U, ApplyFont = true };
            var CellFormatFontAndBorder = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 1U, FormatId = 0U, ApplyFont = true, ApplyBorder = true };
            var CellFormatTitle = new CellFormat() { NumberFormatId = 0U, FontId = 1U, FillId = 0U, BorderId = 0U, FormatId = 0U, Alignment = new Alignment() { Vertical = VerticalAlignmentValues.Center, WrapText = true, Horizontal = HorizontalAlignmentValues.Center }, ApplyFont = true };

            CellFormats.Append(CellFormatFont);
            CellFormats.Append(CellFormatFontAndBorder);
            CellFormats.Append(CellFormatTitle);

            var CellStyles = new CellStyles() { Count = 1U };

            CellStyles.Append(new CellStyle() { Name = "Normal", FormatId = 0U, BuiltinId = 0U });

            var DifferentialFormats = new DocumentFormat.OpenXml.Office2013.Excel.DifferentialFormats() { Count = 0U };

            var TableStyles = new TableStyles() { Count = 0U, DefaultTableStyle = "TableStyleMedium2", DefaultPivotStyle = "PivotStyleLight16" };

            var StylesheetExtensionList = new StylesheetExtensionList();

            var StylesheetExtension1 = new StylesheetExtension() { Uri = "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}" };
            StylesheetExtension1.AddNamespaceDeclaration("x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
            StylesheetExtension1.Append(new SlicerStyles() { DefaultSlicerStyle = "SlicerStyleLight1" });

            var StylesheetExtension2 = new StylesheetExtension() { Uri = "{9260A510-F301-46a8-8635-F512D64BE5F5}" };
            StylesheetExtension2.AddNamespaceDeclaration("x15", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main");
            StylesheetExtension2.Append(new TimelineStyles() { DefaultTimelineStyle = "TimeSlicerStyleLight1" });

            StylesheetExtensionList.Append(StylesheetExtension1);
            StylesheetExtensionList.Append(StylesheetExtension2);

            sp.Stylesheet.Append(Fonts);
            sp.Stylesheet.Append(Fills);
            sp.Stylesheet.Append(Borders);
            sp.Stylesheet.Append(CellStyleFormats);
            sp.Stylesheet.Append(CellFormats);
            sp.Stylesheet.Append(CellStyles);
            sp.Stylesheet.Append(DifferentialFormats);
            sp.Stylesheet.Append(TableStyles);
            sp.Stylesheet.Append(StylesheetExtensionList);
        }

        private static uint GetStyleValue(ExcelStyleInfoType StyleInfo)
        {
            return StyleInfo switch
            {
                ExcelStyleInfoType.Title => 2U,
                ExcelStyleInfoType.TextWithBroder => 1U,
                ExcelStyleInfoType.Text => 0U,
                _ => 0U,
            };
        }

        protected override void CreateExcel(ExcelInfo Info)
        {
            _spreadsheetDocument = SpreadsheetDocument.Create(Info.FileName, SpreadsheetDocumentType.Workbook);

            var WorkbookPart = _spreadsheetDocument.AddWorkbookPart();
            WorkbookPart.Workbook = new Workbook();

            CreateStyles(WorkbookPart);

            _shareStringPart = _spreadsheetDocument.WorkbookPart!.GetPartsOfType<SharedStringTablePart>().Any()
                ? _spreadsheetDocument.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First()
                : _spreadsheetDocument.WorkbookPart.AddNewPart<SharedStringTablePart>();

            // Создаем SharedStringTable, если его нет
            if (_shareStringPart.SharedStringTable == null)
            {
                _shareStringPart.SharedStringTable = new SharedStringTable();
            }

            // Создаем лист в книгу
            var WorksheetPart = WorkbookPart.AddNewPart<WorksheetPart>();
            WorksheetPart.Worksheet = new Worksheet(new SheetData());

            // Добавляем лист в книгу
            var Sheets = _spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets());
            var Sheet = new Sheet()
            {
                Id = _spreadsheetDocument.WorkbookPart.GetIdOfPart(WorksheetPart),
                SheetId = 1,
                Name = "Лист"
            };
            
            Sheets.Append(Sheet);

            _worksheet = WorksheetPart.Worksheet;
        }

        protected override void InsertCellInWorksheet(ExcelCellParameters ExcelParams)
        {
            if (_worksheet == null || _shareStringPart == null)
            {
                return;
            }
            var SheetData = _worksheet.GetFirstChild<SheetData>();
            if (SheetData == null)
            {
                return;
            }

            // Ищем строку, либо добавляем ее
            Row row;
            if (SheetData.Elements<Row>().Where(r => r.RowIndex! == ExcelParams.RowIndex).Any())
            {
                row = SheetData.Elements<Row>().Where(r => r.RowIndex! == ExcelParams.RowIndex).First();
            }
            else
            {
                row = new Row() { RowIndex = ExcelParams.RowIndex };
                SheetData.Append(row);
            }

            // Ищем нужную ячейку  
            Cell cell;
            if (row.Elements<Cell>().Where(c => c.CellReference!.Value == ExcelParams.CellReference).Any())
            {
                cell = row.Elements<Cell>().Where(c => c.CellReference!.Value == ExcelParams.CellReference).First();
            }
            else
            {
                // Все ячейки должны быть последовательно друг за другом расположены
                // нужно определить, после какой вставлять
                Cell? refCell = null;
                foreach (Cell rowCell in row.Elements<Cell>())
                {
                    if (string.Compare(rowCell.CellReference!.Value, ExcelParams.CellReference, true) > 0)
                    {
                        refCell = rowCell;
                        break;
                    }
                }

                var NewCell = new Cell() { CellReference = ExcelParams.CellReference };
                row.InsertBefore(NewCell, refCell);

                cell = NewCell;
            }

            // вставляем новый текст
            _shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new Text(ExcelParams.Text)));
            _shareStringPart.SharedStringTable.Save();

            cell.CellValue = new CellValue((_shareStringPart.SharedStringTable.Elements<SharedStringItem>().Count() - 1).ToString());
            cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
            cell.StyleIndex = GetStyleValue(ExcelParams.StyleInfo);
        }

        protected override void MergeCells(ExcelMergeParameters ExcelParams)
        {
            if (_worksheet == null)
            {
                return;
            }
            MergeCells MergeCells;

            if (_worksheet.Elements<MergeCells>().Any())
            {
                MergeCells = _worksheet.Elements<MergeCells>().First();
            }
            else
            {
                MergeCells = new MergeCells();

                if (_worksheet.Elements<CustomSheetView>().Any())
                {
                    _worksheet.InsertAfter(MergeCells, _worksheet.Elements<CustomSheetView>().First());
                }
                else
                {
                    _worksheet.InsertAfter(MergeCells, _worksheet.Elements<SheetData>().First());
                }
            }

            var MergeCell = new MergeCell()
            {
                Reference = new StringValue(ExcelParams.Merge)
            };
            
            MergeCells.Append(MergeCell);
        }

        protected override void SaveExcel(ExcelInfo Info)
        {
            if (_spreadsheetDocument == null)
                return;

            _spreadsheetDocument.WorkbookPart!.Workbook.Save();
            _spreadsheetDocument.Close();
        }
    }
}
