using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using MessagePack;
using MessagePack.Formatters;
using MessagePack.Resolvers;

namespace X2Tests
{
  [MessagePackObject]
  public class Test
  {
      [Key(0)]
      public int A { get; set; }
      [Key(1)]
      public string B { get; set; }
      [Key(2)]
      // public string C { get; set; }
      public object Argument;
  }
  
  public class MyExtensionResolver : IFormatterResolver
  {
      public static readonly IFormatterResolver Instance = new MyExtensionResolver();

      public IMessagePackFormatter<T> GetFormatter<T>()
      {
          return Cache<T>.formatter;
      }

      static class Cache<T>
      {
          public static IMessagePackFormatter<T> formatter;

          static Cache()
          {
              formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(typeof(MyExtensionFormatter<>).MakeGenericType(typeof(T)), new object[]
              {
                  // customize your inner resolver.
                  MessagePack.Resolvers.StandardResolver.Instance
              });
          }
      }
  }

  public class MyExtensionFormatter<T> : IMessagePackFormatter<T>
  {
      readonly IFormatterResolver innerResolver;

      public MyExtensionFormatter(IFormatterResolver innerResolver)
      {
          this.innerResolver = innerResolver;
      }

      public int Serialize(ref byte[] bytes, int offset, T value, IFormatterResolver formatterResolver)
      {
          // serialize...
          return 0;
      }

      public T Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
      {
          int size;
          if (MessagePackBinary.GetMessagePackType(bytes, offset) == MessagePackType.Extension)
          {
              var header = MessagePackBinary.ReadExtensionFormatHeader(bytes, offset, out size);
              if (header.TypeCode == 111/* Your own ext code */)
              {
                  readSize = 9999; // :)
                  dynamic ret = new string[]{"one", "two"};
                  // return (T)(object)"test...test";
                  return ret;
              }
          }
         
         // innerResolver is StandardResolver
          return innerResolver.GetFormatter<T>().Deserialize(bytes, offset, formatterResolver, out readSize); ;
      }
  }
  
  
  [TestClass]
  public class SandboxTest
  {
    [TestMethod]
    public void TestMethod1()
    {
      byte[] bytes = null;
      var offset = 0;
      offset += MessagePack.MessagePackBinary.WriteArrayHeader(ref bytes, offset, 3);
      offset += MessagePack.MessagePackBinary.WriteInt32(ref bytes, offset, 2);
      offset += MessagePack.MessagePackBinary.WriteString(ref bytes, offset, "hello");
      
      // this works
      // offset += MessagePack.MessagePackBinary.WriteExtensionFormat(ref bytes, offset, 111, new byte[] { 1, 10, 100, 200 });
      
      // this does not
      offset += MessagePackBinary.WriteMapHeader(ref bytes, offset, 1);
      offset += MessagePack.MessagePackBinary.WriteString(ref bytes, offset, "object");
      offset += MessagePack.MessagePackBinary.WriteExtensionFormat(ref bytes, offset, 111, new byte[] { 1, 10, 100, 200 });
      

      var result = MessagePackSerializer.Deserialize<Test>(bytes, MyExtensionResolver.Instance);
      Console.WriteLine(result);
    }
    
  }
}