using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using A = DocumentFormat.OpenXml.Drawing;
using Xdr = DocumentFormat.OpenXml.Drawing.Spreadsheet;

namespace OnlineSalesAutoCrop.CoreAPI.Models.Global
{
	internal static class ExcelTools
	{
		private static PartTypeInfo GetImagePartTypeByBitmap(byte[] bytes)
		{
			byte[] tiff = "II*"u8.ToArray();                // TIFF
			byte[] tiff2 = "MM*"u8.ToArray();               // TIFF
			byte[] jpeg = [255, 216, 255];                  // jpeg
			byte[] bmp = Encoding.ASCII.GetBytes("BM");     // BMP
			byte[] gif = Encoding.ASCII.GetBytes("GIF");    // GIF
			byte[] png = [137, 80, 78, 71];                 // PNG

			if (bmp.SequenceEqual(bytes.Take(bmp.Length)))
				return ImagePartType.Bmp;
			else if (gif.SequenceEqual(bytes.Take(gif.Length)))
				return ImagePartType.Gif;
			else if (png.SequenceEqual(bytes.Take(png.Length)))
				return ImagePartType.Png;
			else if (tiff.SequenceEqual(bytes.Take(tiff.Length)))
				return ImagePartType.Tiff;
			else if (tiff2.SequenceEqual(bytes.Take(tiff2.Length)))
				return ImagePartType.Tiff;
			else if (jpeg.SequenceEqual(bytes.Take(jpeg.Length)))
				return ImagePartType.Jpeg;

			throw new InvalidOperationException("Image type could not be determined.");
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="worksheetPart"></param>
		/// <param name="stream"></param>
		/// <param name="imgDescription"></param>
		/// <param name="colNumber"></param>
		/// <param name="rowNumber"></param>
		public static void AddImage(WorksheetPart worksheetPart, Stream stream, string imgDescription, int colNumber, int rowNumber)
		{
			var drawingsPart = worksheetPart.DrawingsPart;
			drawingsPart ??= worksheetPart.AddNewPart<DrawingsPart>();

			if (!worksheetPart.Worksheet.ChildElements.OfType<Drawing>().Any())
				worksheetPart.Worksheet.AppendChild(new Drawing { Id = worksheetPart.GetIdOfPart(drawingsPart) });

			drawingsPart.WorksheetDrawing ??= new Xdr.WorksheetDrawing();
			var worksheetDrawing = drawingsPart.WorksheetDrawing;

			ImagePart imagePart;
			long extentsCx = 0, extentsCy = 0;
			using (MemoryStream ms = new())
			{
				stream.Position = 0;
				stream.CopyTo(ms);
				stream.Position = 0;
#pragma warning disable CA1416 // Validate platform compatibility
				using Bitmap bmp = new(ms);
				imagePart = drawingsPart.AddImagePart(GetImagePartTypeByBitmap(ms.ToArray()));
				imagePart.FeedData(stream);

				extentsCx = bmp.Width * (long)(914400 / bmp.HorizontalResolution);
				extentsCy = bmp.Height * (long)(914400 / bmp.VerticalResolution);
#pragma warning restore CA1416 // Validate platform compatibility
			}

			uint nvpId = worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>().Any() ? (UInt32Value)worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>().Max(p => p.Id.Value) + 1 : 1U;
			Xdr.OneCellAnchor oneCellAnchor = new(
				new Xdr.FromMarker
				{
					ColumnId = new Xdr.ColumnId((colNumber - 1).ToString()),
					RowId = new Xdr.RowId((rowNumber - 1).ToString()),
					ColumnOffset = new Xdr.ColumnOffset("0"),
					RowOffset = new Xdr.RowOffset("0")
				},
				new Xdr.Extent { Cx = extentsCx, Cy = extentsCy },
				new Xdr.Picture(
					new Xdr.NonVisualPictureProperties(
						new Xdr.NonVisualDrawingProperties { Id = nvpId, Name = "Picture " + nvpId, Description = imgDescription },
						new Xdr.NonVisualPictureDrawingProperties(new A.PictureLocks { NoChangeAspect = true })
					),
					new Xdr.BlipFill(
						new A.Blip { Embed = drawingsPart.GetIdOfPart(imagePart), CompressionState = A.BlipCompressionValues.Print },
						new A.Stretch(new A.FillRectangle())
					),
					new Xdr.ShapeProperties(
						new A.Transform2D(
							new A.Offset { X = 0, Y = 0 },
							new A.Extents { Cx = extentsCx, Cy = extentsCy }
						),
						new A.PresetGeometry { Preset = A.ShapeTypeValues.Rectangle }
					)
				),
				new Xdr.ClientData()
			);

			worksheetDrawing.Append(oneCellAnchor);
		}
	}
}
