using System.Globalization;
using System.Xml;

using ThingsGateway.NewLife.Collections;
using ThingsGateway.NewLife.Reflection;

namespace ThingsGateway.NewLife.Serialization;

/// <summary>Xml基础类型处理器</summary>
public class XmlGeneral : XmlHandlerBase
{
    /// <summary>实例化</summary>
    public XmlGeneral()
    {
        Priority = 10;
    }

    /// <summary>写入一个对象</summary>
    /// <param name="value">目标对象</param>
    /// <param name="type">类型</param>
    /// <returns>是否处理成功</returns>
    public override Boolean Write(Object? value, Type type)
    {
        //if (value == null && type != typeof(String)) return false;

        var writer = Host.GetWriter();

        // 枚举 写入字符串
        if (type.IsEnum)
        {
            if (Host is Xml xml && xml.EnumString)
                writer.WriteValue(value + "");
            else
                writer.WriteValue(value.ToLong());

            return true;
        }

        switch (type.GetTypeCode())
        {
            case TypeCode.Boolean:
                writer.WriteValue((Boolean)(value ?? false));
                return true;
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.Char:
                writer.WriteValue(Convert.ToChar(value));
                return true;
            case TypeCode.DBNull:
            case TypeCode.Empty:
                writer.WriteValue(0);
                return true;
            case TypeCode.DateTime:
                writer.WriteValue(((DateTime)(value ?? DateTime.MinValue)).ToFullString());
                return true;
            case TypeCode.Decimal:
                writer.WriteValue((Decimal)(value ?? 0m));
                return true;
            case TypeCode.Double:
                writer.WriteValue((Double)(value ?? 0d));
                return true;
            case TypeCode.Single:
                writer.WriteValue((Single)(value ?? 0f));
                return true;
            case TypeCode.Int16:
            case TypeCode.UInt16:
            case TypeCode.Int32:
            case TypeCode.UInt32:
                writer.WriteValue(Convert.ToInt32(value));
                return true;
            case TypeCode.Int64:
            case TypeCode.UInt64:
                writer.WriteValue(Convert.ToInt64(value));
                return true;
            case TypeCode.String:
                writer.WriteValue(value + "");
                return true;
            case TypeCode.Object:
                break;
            default:
                break;
        }

        if (type == typeof(Guid))
        {
            if (value is Guid guid) writer.WriteValue((guid).ToString());
            return true;
        }

        if (type == typeof(DateTimeOffset))
        {
            //writer.WriteValue((DateTimeOffset)value);
            if (value is DateTimeOffset dto) writer.WriteValue(dto + "");
            return true;
        }

        if (type == typeof(TimeSpan))
        {
            if (value is TimeSpan ts) writer.WriteValue(ts + "");
            return true;
        }

        if (type == typeof(Byte[]))
        {
            if (value is Byte[] buf) writer.WriteBase64(buf, 0, buf.Length);
            return true;
        }

        if (type == typeof(Char[]))
        {
            if (value is Char[] cs) writer.WriteValue(new String(cs));
            return true;
        }

        // 支持格式化的类型，有去有回
        if (type.As<IFormattable>())
        {
            if (value is IFormattable ft) writer.WriteValue(ft + "");
            return true;
        }

        return false;
    }

    /// <summary>尝试读取</summary>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public override Boolean TryRead(Type type, ref Object? value)
    {
        if (type == null)
        {
            if (value == null) return false;
            type = value.GetType();
        }

        var reader = Host.GetReader();

        if (type == typeof(Guid))
        {
            value = new Guid(reader.ReadContentAsString());
            return true;
        }
        else if (type == typeof(Byte[]))
        {
            // 用字符串长度作为预设缓冲区的长度
            var buf = Pool.Shared.Rent(reader.Value.Length);
            var count = reader.ReadContentAsBase64(buf, 0, buf.Length);
            value = buf.ReadBytes(0, count);
            Pool.Shared.Return(buf);

            return true;
        }
        else if (type == typeof(Char[]))
        {
            value = reader.ReadContentAsString().ToCharArray();
            return true;
        }
        else if (type == typeof(DateTimeOffset))
        {
            //value = reader.ReadContentAs(type, null);
            value = DateTimeOffset.Parse(reader.ReadContentAsString());
            return true;
        }
        else if (type == typeof(TimeSpan))
        {
            value = TimeSpan.Parse(reader.ReadContentAsString());
            return true;
        }

        type = Nullable.GetUnderlyingType(type) ?? type;
        if (!type.IsBaseType()) return false;

        // 读取异构Xml时可能报错
        var v = (reader.NodeType == XmlNodeType.Element ? reader.ReadElementContentAsString() : reader.ReadContentAsString()) + "";

        // 枚举
        if (type.IsEnum)
        {
            value = Enum.Parse(type, v);
            return true;
        }

        switch (type.GetTypeCode())
        {
            case TypeCode.Boolean:
                value = v.ToBoolean();
                return true;
            case TypeCode.Byte:
                value = Byte.Parse(v, NumberStyles.HexNumber);
                return true;
            case TypeCode.Char:
                if (v.Length > 0) value = v[0];
                return true;
            case TypeCode.DBNull:
                value = DBNull.Value;
                return true;
            case TypeCode.DateTime:
                value = v.ToDateTime();
                return true;
            case TypeCode.Decimal:
                value = (Decimal)v.ToDouble();
                return true;
            case TypeCode.Double:
                value = v.ToDouble();
                return true;
            case TypeCode.Empty:
                value = null;
                return true;
            case TypeCode.Int16:
                value = (Int16)v.ToInt();
                return true;
            case TypeCode.Int32:
                value = v.ToInt();
                return true;
            case TypeCode.Int64:
                value = Int64.Parse(v);
                return true;
            case TypeCode.Object:
                break;
            case TypeCode.SByte:
                value = SByte.Parse(v, NumberStyles.HexNumber);
                return true;
            case TypeCode.Single:
                value = (Single)v.ToDouble();
                return true;
            case TypeCode.String:
                value = v;
                return true;
            case TypeCode.UInt16:
                value = (UInt16)v.ToInt();
                return true;
            case TypeCode.UInt32:
                value = (UInt32)v.ToInt();
                return true;
            case TypeCode.UInt64:
                value = UInt64.Parse(v);
                return true;
            default:
                break;
        }

#if NET7_0_OR_GREATER
        if (type.GetInterfaces().Any(e => e.IsGenericType && e.GetGenericTypeDefinition() == typeof(IParsable<>)))
        {
            value = reader.ReadContentAsString().ChangeType(type);
            return true;
        }
#endif

        return false;
    }
}