using FastReport;
using FastReport.Utils;
using InABox.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Drawing;

namespace InABox.Wpf.Reports.CustomObjects
{

    public class MultiImageObject : MultiItemObject
    {

        private List<byte[]>? imageData { get; set; }

        [Category("Data")]
        public string? DataColumn { get; set; }

        [Category("Data")]
        public List<Image>? Images { get; set; }

        public override void GetData()
        {
            base.GetData();
            if (!string.IsNullOrEmpty(DataColumn))
            {
                // reset the image
                Images = null;
                imageData = null;

                object data = Report.GetColumnValueNullable(DataColumn);
                if (data is List<byte[]> list)
                {
                    SetImageData(list);
                }
                else if (data is IEnumerable<byte[]> enumerable)
                {
                    SetImageData(enumerable);
                }
            }
        }

        private void SetImageData(IEnumerable<byte[]> imageData)
        {
            this.imageData = imageData.ToList();
        }
        private void SetImageData(List<byte[]> imageData)
        {
            this.imageData = imageData.ToList();
        }

        private class ImageItem : Item
        {
            public Image Image;

            public float Width => Image.Width;
            public float Height => Image.Height;

            public ImageItem(Image image)
            {
                Image = image;
            }
        }

        #region Serialization

        public override void Serialize(FRWriter writer)
        {
            base.Serialize(writer);
            if(writer.DiffObject is MultiImageObject c)
            {
                if (DataColumn != c.DataColumn)
                    writer.WriteValue("DataColumn", DataColumn);

                if (writer.SerializeTo != SerializeTo.SourcePages)
                {
                    if (writer.SerializeTo == SerializeTo.Preview || String.IsNullOrEmpty(DataColumn))
                    {
                        if (Images == null && imageData != null)
                            writer.WriteStr("Images", Serialization.Serialize(imageData));
                        else if (!writer.AreEqual(Images, c.Images))
                            writer.WriteValue("Images", Images);
                    }
                }
            }
        }

        public override void Deserialize(FRReader reader)
        {
            base.Deserialize(reader);
            if (reader.HasProperty("Images"))
            {
                SetImageData(Serialization.Deserialize<List<byte[]>>(reader.ReadStr("Images")));
            }
        }

        #endregion

        public override void Assign(Base source)
        {
            base.Assign(source);

            if (source is MultiImageObject src)
            {
                DataColumn = src.DataColumn;

                Images = src.Images == null ? null : src.Images.Select(x => x.Clone() as Image).ToList();
                if(src.Images == null && src.imageData != null)
                {
                    imageData = src.imageData;
                }
            }
        }

        #region Drawing

        public static Image? Load(byte[] bytes)
        {
            if (bytes != null && bytes.Length > 0)
            {
                try
                {
#if CROSSPLATFORM
                    // TODO memory leaks image converter
                    return Image.FromStream(new MemoryStream(bytes));
#else
                    return new ImageConverter().ConvertFrom(bytes) as Image;
#endif

                }
                catch
                {
                    Bitmap errorBmp = new Bitmap(10, 10);
                    using (Graphics g = Graphics.FromImage(errorBmp))
                    {
                        g.DrawLine(Pens.Red, 0, 0, 10, 10);
                        g.DrawLine(Pens.Red, 0, 10, 10, 0);
                    }
                    return errorBmp;
                }
            }
            return null;
        }

        private void LoadImages()
        {
            if (imageData == null) return;

            Images = new();
            for(int i = 0; i < imageData.Count; i++) {
                var saveImageData = imageData[i];
                // FImageData will be reset after this line, keep it
                var newImage = Load(imageData[i]);
                if(newImage != null)
                {
                    Images.Add(newImage);
                }
                imageData[i] = saveImageData;
            }
        }

        protected override void DrawItem(FRPaintEventArgs e, Item item, float x, float y, float w, float h)
        {
            if(item is ImageItem image)
            {
                e.Graphics.DrawImage(image.Image, x * e.ScaleX, y * e.ScaleY, w * e.ScaleX, h * e.ScaleY);
            }
        }

        protected override IList<Item>? LoadItems()
        {
            if (Images == null)
            {
                LoadImages();
            }
            if (Images == null)
            {
                return null;
            }
            return Images.Select(x => new ImageItem(x) as Item).ToList();
        }

        #endregion
    }
}
