using System;
using System.Linq;
using Avalonia.Controls;

namespace detect.gui.Commons;

public static class ClassHelper
{
    public static object? GetValue<S>(this S source, string name)
    {
        var sp = (source?.GetType().GetProperties() ?? throw new InvalidOperationException()).FirstOrDefault(p =>
            p.Name == name);
        return sp == null ? default : sp.GetValue(source);
    }

    public static string GetFullName(this string typeName)
    {
        return "detect.gui.ViewModels." + typeName;
    }

    public static Type? GetTypeByName(this string typeName)
    {
        Type? type = null;
        var assemblyArray = AppDomain.CurrentDomain.GetAssemblies();
        var assemblyArrayLength = assemblyArray.Length;
        for (var i = 0; i < assemblyArrayLength; ++i)
        {
            type = assemblyArray[i].GetType(typeName);
            if (type != null)
            {
                return type;
            }
        }
 
        for (var i = 0; (i < assemblyArrayLength); ++i)
        {
            var typeArray = assemblyArray[i].GetTypes();
            var typeArrayLength = typeArray.Length;
            for (var j = 0; j < typeArrayLength; ++j)
            {
                if (typeArray[j].Name.Equals(typeName))
                {
                    return typeArray[j];
                }
            }
        }
        return type;
    }
    
    public static T? GetParent<T>(this Control control, string? name = null) where T : Control
    {
        var parent = control.Parent;
        while (parent != null)
        {
            if (parent is T)
            {
                if (name == null) break;
                if (parent.Name == name) break;
            }

            parent = parent.Parent;
        }

        return (T?)parent;
    }
    
    public static T Convert<S, T>(this S source)
    {
        var target = Activator.CreateInstance<T>();
        var sourcePropertyList = typeof(S).GetProperties().ToList();
        var targetPropertyList = typeof(T).GetProperties().ToList();
        foreach (var sourceProperty in sourcePropertyList)
        {
            if (sourceProperty.DeclaringType?.FullName == "ReactiveUI.ReactiveObject") continue;
            var sp = (source?.GetType().GetProperties() ?? throw new InvalidOperationException()).FirstOrDefault(p =>
                p.Name == sourceProperty.Name);
            if (sp == null) continue;
            var value = sp.GetValue(source);
            if (value == null) continue;
            var cnt = targetPropertyList.Count(p => p.Name == sp.Name);
            if (cnt == 0) continue;
            var targetProperty = targetPropertyList.Where(p => p.Name == sp.Name).ToArray()[0];
            targetProperty.SetValue(target, value);
        }
        return target;
    }

    private static object ConvertType(object? convertibleValue, Type type)
    {
        if (convertibleValue == null) throw new Exception("Value is null"); //convertibleValue));
        if (!type.IsGenericType)
        {
            return System.Convert.ChangeType(convertibleValue, type);
        }
    
        var genericTypeDefinition = type.GetGenericTypeDefinition();
        if (genericTypeDefinition == typeof(Nullable<>))
        {
            var ddd = Nullable.GetUnderlyingType(type);
            return System.Convert.ChangeType(convertibleValue,
                Nullable.GetUnderlyingType(type) ?? throw new InvalidOperationException(
                    $"Invalid cast from type \"{convertibleValue.GetType().FullName}\" to type \"{type.FullName}\"."));
        }
    
        throw new InvalidCastException(
            $"Invalid cast from type \"{convertibleValue.GetType().FullName}\" to type \"{type.FullName}\".");
    }
}