using System.Data;
using Dapper;
using SatelliteProvider.Common.Enums;

namespace SatelliteProvider.DataAccess.TypeHandlers;

public class EnumStringTypeHandler<T> : SqlMapper.TypeHandler<T> where T : struct, Enum
{
    public override T Parse(object value)
    {
        if (value is null || value is DBNull)
        {
            throw new DataException($"Cannot parse null DB value into enum {typeof(T).Name}");
        }

        var s = value as string ?? value.ToString();
        if (string.IsNullOrEmpty(s))
        {
            throw new DataException($"Cannot parse empty DB value into enum {typeof(T).Name}");
        }

        if (!Enum.TryParse<T>(s, ignoreCase: true, out var parsed) || !Enum.IsDefined(parsed))
        {
            throw new DataException($"DB value '{s}' is not a defined member of enum {typeof(T).Name}");
        }

        return parsed;
    }

    public override void SetValue(IDbDataParameter parameter, T value)
    {
        parameter.Value = value.ToString().ToLowerInvariant();
        parameter.DbType = DbType.String;
    }
}

public static class DapperEnumTypeHandlers
{
    private static int _registered;

    public static void RegisterAll()
    {
        if (Interlocked.Exchange(ref _registered, 1) == 1)
        {
            return;
        }

        SqlMapper.AddTypeHandler(new EnumStringTypeHandler<RegionStatus>());
        SqlMapper.AddTypeHandler(new EnumStringTypeHandler<RoutePointType>());
    }
}
