using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using bitforum.Models;

namespace bitforum.Helpers
{
    public static class Functions
    {
        // SaveConfig 함수는 Config 모델에 대한 정보를 저장하는 함수
        public static void SaveConfig<T>(T request, Action<Config> saveAction)
        {
            var properties = typeof(T).GetProperties();

            foreach (var property in properties)
            {
                var key = (property.GetCustomAttribute<BindPropertyAttribute>()?.Name ?? property.Name); // 속성 Key 이름
                var value = property.GetValue(request)?.ToString(); // 속성 값
                var displayName = (property.GetCustomAttribute<DisplayAttribute>()?.Name ?? key); // 속성 표시 이름

                saveAction(new Config
                {
                    Key = key,
                    Value = value,
                    Description = displayName
                });
            }
        }

        // Config 값 조회
        public static string? GetConfig(this Dictionary<string, string> config, string k, string? d = null)
        {
            return config.TryGetValue(k, out var v) ? v : d;
        }

        // 날짜 포맷 조회
        public static string GetDateAt(this DateTime? dateTime, string format = "yyyy.MM.dd HH:mm:ss") => dateTime?.ToString(format) ?? string.Empty;
        public static string GetDateAt(this DateTime dateTime, string format = "yyyy.MM.dd HH:mm:ss") => dateTime.ToString(format);
        
        // ModelState 오류 조회
        public static Dictionary<string, List<string>> GetErrors(this ModelStateDictionary modelState)
        {
            return modelState.Where(ms => ms.Value.Errors.Any()).ToDictionary(
                ms => ms.Key,
                ms => ms.Value.Errors.Select(e => e.ErrorMessage).ToList()
            );
        }

        // Client IP 조회
        public static string GetClientIP(this HttpContext context)
        {
            return context.Request.Headers["X-Forwarded-For"].FirstOrDefault() ?? context.Connection.RemoteIpAddress?.ToString() ?? "Unknown";
        }

        // Dictionary 데이터를 특정 객체에 자동 매핑
        public static T Mapping<T>(Dictionary<string, string> dict) where T : new()
        {
            var obj = new T();
            var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var prop in properties)
            {
                var key = prop.GetCustomAttribute<BindPropertyAttribute>()?.Name ?? prop.Name;

                if (dict.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value))
                {
                    try
                    {
                        prop.SetValue(obj, ConvertValue(value, prop.PropertyType));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"`{prop.Name}` 객체 변환 오류: {ex.Message}");
                    }
                }
            }

            return obj;
        }

        // 문자열 값을 해당 프로퍼티 타입으로 자동 변환
        public static object? ConvertValue(string value, Type t)
        {
            if (string.IsNullOrEmpty(value))
            {
                return null;
            }else if (Nullable.GetUnderlyingType(t) is Type underlyingType) {
                t = underlyingType; 
            }
            if (t == typeof(bool) && bool.TryParse(value, out bool boolValue)) {
                return boolValue;
            }else if (t == typeof(byte) && byte.TryParse(value, out byte byteValue)) {
                return byteValue;
            }else if (t == typeof(sbyte) && sbyte.TryParse(value, out sbyte sbyteValue)) {
                return sbyteValue;
            }else if (t == typeof(char) && value.Length > 0) {
                return value[0];
            }else if (t == typeof(short) && short.TryParse(value, out short shortValue)) {
                return shortValue;
            }else if (t == typeof(ushort) && ushort.TryParse(value, out ushort ushortValue)) {
                return ushortValue;
            }else if (t == typeof(int) && int.TryParse(value, out int intValue)) {
                return intValue;
            }else if (t == typeof(uint) && uint.TryParse(value, out uint uintValue)) {
                return uintValue;
            }else  if (t == typeof(long) && long.TryParse(value, out long longValue)) {
                return longValue;
            }else if (t == typeof(ulong) && ulong.TryParse(value, out ulong ulongValue)) {
                return ulongValue;
            }else if (t == typeof(float) && float.TryParse(value, out float floatValue)) {
                return floatValue;
            }else if (t == typeof(double) && double.TryParse(value, out double doubleValue)) {
                return doubleValue;
            }else if (t == typeof(decimal) && decimal.TryParse(value, out decimal decimalValue)) {
                return decimalValue;
            }else if (t == typeof(DateTime) && DateTime.TryParse(value, out DateTime dateTimeValue)) {
                return dateTimeValue;
            }else if (t == typeof(Guid) && Guid.TryParse(value, out Guid guidValue)) {
                return guidValue;
            }
            return value;
        }
    }
}
