using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Globalization;

/// <summary>
/// Summary description for SalesforceNilConverter
/// </summary>
public class SalesforceNilConverter : JsonConverter
{

    string[] acceptedFormats = { "yyyy-MM-dd'T'HH.mm.ssZ", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd'T'HH.mm.ss", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH.mm.ss", "dd-MM-yyyy HH:mm:ss", "dd/MM/yyyy HH:mm:ss", "MM/dd/yyyy HH:mm:ss", "yyyy-MM-dd", };

    public DateTime? ValidateDateTime(string input, string[] formats)
    {
        DateTime result;
        bool isValid = DateTime.TryParseExact(
            input,
            formats,
            CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
            out result
        );

        if (isValid)
        {
            string matchedFormat = "Unknown";

            foreach (var fmt in formats)
            {
                DateTime tempResult;
                if (DateTime.TryParseExact(
                    input,
                    fmt,
                    CultureInfo.InvariantCulture,
                    DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
                    out tempResult))
                {
                    matchedFormat = fmt;
                    break;
                }
            }

            return result;
        }

        return null;
    }
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string)
            || objectType == typeof(DateTime?)
            || objectType == typeof(DateTime);
    }

    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {

        if (reader.TokenType == JsonToken.Null)
            return null;

        // Plain string value
        if (reader.TokenType == JsonToken.String)
        {


            var raw = reader.Value!= null ? reader.Value.ToString():"";
            if (objectType == typeof(DateTime?) || objectType == typeof(DateTime))
                return string.IsNullOrEmpty(raw) ? (object)null : ValidateDateTime(raw, acceptedFormats);
            return raw;
        }

        // Salesforce nil object: { "@nil": "true" }
        if (reader.TokenType == JsonToken.StartObject)
        {
            var jObj = JObject.Load(reader);
            if (jObj["@nil"]!= null && jObj["@nil"].ToString() == "true")
                return null;

            // Handle actual value inside object if present
            var val = jObj["$value"]!= null ? jObj["$value"].ToString():null;
            if (val != null && (objectType == typeof(DateTime?) || objectType == typeof(DateTime)))
                return DateTime.Parse(val);

            return val;
        }

        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}