using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace InABox.Core
{

    public class CoreTableJsonConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
        {
            if(!(value is CoreTable table))
            {
                writer.WriteNull();
                return;
            }

            writer.WriteStartObject();
            writer.WritePropertyName("Columns");
            var cols = new Dictionary<string, string>();
            foreach (var column in table.Columns)
                cols[column.ColumnName] = column.DataType.EntityName();
            serializer.Serialize(writer, cols);
            //writer.WriteEndObject();

            //writer.WriteStartObject();
            writer.WritePropertyName("Rows");
            writer.WriteStartArray();
            var size = 0;
            foreach (var row in table.Rows)
                //Console.WriteLine("- Serializing Row #"+row.Index.ToString());
                try
                {
                    writer.WriteStartArray();
                    foreach (var col in table.Columns)
                    {
                        var val = row[col.ColumnName];
                        if (val != null) size += val.ToString().Length;
                        //Console.WriteLine(String.Format("Serializing Row #{0} Column [{1}] Length={2}", row.Index.ToString(), col.ColumnName, val.ToString().Length));
                        if (col.DataType.IsArray && val != null)
                        {
                            writer.WriteStartArray();
                            foreach (var val1 in (Array)val)
                                writer.WriteValue(val1);
                            writer.WriteEndArray();
                        }
                        else if (col.DataType.GetInterfaces().Contains(typeof(IPackableList)))
                        {
                            writer.WriteStartArray();
                            foreach (var val1 in (IList)val)
                                writer.WriteValue(val1);
                            writer.WriteEndArray();
                        }
                        else
                        {
                            writer.WriteValue(val ?? CoreUtils.GetDefault(col.DataType));
                        }
                    }

                    writer.WriteEndArray();
                    //Console.WriteLine(String.Format("[{0:D8}] Serializing Row #{1}", size, row.Index.ToString()));
                }
                catch (Exception e)
                {
                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
                }

            writer.WriteEndArray();
            writer.WriteEndObject();
        }

        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;

            var result = new CoreTable();
            try
            {
                var json = JObject.Load(reader);
                if (json.TryGetValue("Columns", out var columns))
                {
                    foreach (JProperty column in columns.Children())
                    {
                        var name = column.Name;
                        var type = column.Value.ToObject<string>();
                        result.Columns.Add(new CoreColumn { ColumnName = name, DataType = CoreUtils.GetEntity(type ?? string.Empty) });
                    }
                }

                if (json.TryGetValue("Rows", out var rows))
                {
                    foreach (JArray row in rows.Children())
                        if (row.Children().ToArray().Length == result.Columns.Count)
                        {
                            var newrow = result.NewRow();
                            var iCol = 0;
                            foreach (var cell in row.Children())
                            {
                                var column = result.Columns[iCol];
                                try
                                {
                                    if (column.DataType.IsArray)
                                    {
                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);
                                    }
                                    else if (column.DataType.GetInterfaces().Contains(typeof(IPackableList)))
                                    {
                                    }
                                    else
                                    {
                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);
                                    }
       
                                }
                                catch (Exception e)
                                {
                                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
                                }

                                iCol++;
                            }

                            result.Rows.Add(newrow);
                        }
                }
            }
            catch (Exception e)
            {
                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
            }

            return result;
            
        }


        public override bool CanConvert(Type objectType)
        {
            return typeof(CoreTable).GetTypeInfo().IsAssignableFrom(objectType);
        }
    }
}