using System;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Security;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.UI.Forms;
using MySql.Data.Types;
using mRemoteNG.Resources.Language;
using System.Runtime.Versioning;

namespace mRemoteNG.Tools
{
    [SupportedOSPlatform("windows")]
    public static class MiscTools
    {
        public static Icon? GetIconFromFile(string FileName)
        {
            try
            {
                return File.Exists(FileName) ? Icon.ExtractAssociatedIcon(FileName) : null;
            }
            catch (ArgumentException AEx)
            {
                Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "GetIconFromFile failed (Tools.Misc) - using default icon" + Environment.NewLine + AEx.Message, true);
                return Properties.Resources.mRemoteNG_Icon;
            }
            catch (Exception ex)
            {
                Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "GetIconFromFile failed (Tools.Misc)" + Environment.NewLine + ex.Message, true);
                return null;
            }
        }

        public static Optional<SecureString> PasswordDialog(string? passwordName = null, bool verify = true)
        {
            //var splash = FrmSplashScreenNew.GetInstance();
            //TODO: something not right there 
            //if (PresentationSource.FromVisual(splash))
            //    splash.Close();

            passwordName ??= string.Empty; // Ensure passwordName is not null
            FrmPassword passwordForm = new(passwordName, verify);
            return passwordForm.GetKey();
        }

        public static string LeadingZero(string Number)
        {
            if (Convert.ToInt32(Number) < 10)
            {
                return "0" + Number;
            }

            return Number;
        }

        public static bool GetBooleanValue(object dataObject)
        {
            Type type = dataObject.GetType();

            if (type == typeof(bool))
            {
                return (bool)dataObject;
            }
            if (type == typeof(string))
            {
                return (string)dataObject == "1";
            }
            if (type == typeof(sbyte))
            {
                return (sbyte)dataObject == 1;
            }

            Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Conversion of object to boolean failed because the type, {type}, is not handled.");
            return false;
        }

        public static string DBDate(DateTime Dt)
		{
			switch (Properties.OptionsDBsPage.Default.SQLServerType)
			{
				case "mysql":
					return Dt.ToString("yyyy/MM/dd HH:mm:ss");
				case "mssql":
				default:
					return Dt.ToString("yyyyMMdd HH:mm:ss");
			}
		}

		public static Type DBTimeStampType()
		{
			switch (Properties.OptionsDBsPage.Default.SQLServerType)
			{
				case "mysql":
					return typeof(MySqlDateTime);
				case "mssql":
				default:
					return typeof(SqlDateTime);
			}
		}

		public static object DBTimeStampNow()
		{
			switch (Properties.OptionsDBsPage.Default.SQLServerType)
			{
				case "mysql":
					return new MySqlDateTime(DateTime.Now.ToUniversalTime());
				case "mssql":
				default:
					return DateTime.Now.ToUniversalTime();
			}
		}

        public static string PrepareValueForDB(string Text)
        {
            return Text.Replace("\'", "\'\'");
        }

        public static string GetExceptionMessageRecursive(Exception ex)
        {
            return GetExceptionMessageRecursive(ex, Environment.NewLine);
        }

        private static string GetExceptionMessageRecursive(Exception ex, string separator)
        {
            string message = ex.Message;
            if (ex.InnerException == null) return message;
            string innerMessage = GetExceptionMessageRecursive(ex.InnerException, separator);
            message = String.Join(separator, message, innerMessage);
            return message;
        }


        public static Image? TakeScreenshot(UI.Tabs.ConnectionTab sender)
        {
            try
            {
                if (sender != null)
                {
                    Bitmap bmp = new(sender.Width, sender.Height, PixelFormat.Format32bppRgb);
                    Graphics g = Graphics.FromImage(bmp);
                    g.CopyFromScreen(sender.PointToScreen(System.Drawing.Point.Empty), System.Drawing.Point.Empty, bmp.Size, CopyPixelOperation.SourceCopy);
                    return bmp;
                }
            }
            catch (Exception ex)
            {
                Runtime.MessageCollector.AddExceptionStackTrace("Taking Screenshot failed", ex);
            }

            return null;
        }

        public class EnumTypeConverter(Type type) : EnumConverter(type)
        {
            private readonly Type _enumType = type;

            public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destType)
            {
                return destType == typeof(string);
            }

            public override object ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type? destType)
            {
                if (value == null) return string.Empty;

                string? enumName = Enum.GetName(_enumType, value);
                if (enumName == null)
                {
                    throw new ArgumentException("Invalid enum value provided.");
                }

                System.Reflection.FieldInfo? fi = _enumType.GetField(enumName);
                if (fi == null)
                {
                    throw new ArgumentException("FieldInfo could not be retrieved for the provided enum value.");
                }

                DescriptionAttribute? dna = (DescriptionAttribute?)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
                return dna?.Description ?? value.ToString() ?? string.Empty;
            }

            public override bool CanConvertFrom(ITypeDescriptorContext? context, Type? srcType)
            {
                return srcType == typeof(string);
            }

            public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
            {
                if (value is string stringValue)
                {
                    foreach (System.Reflection.FieldInfo fi in _enumType.GetFields())
                    {
                        DescriptionAttribute? dna = (DescriptionAttribute?)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));

                        if (dna != null && string.Equals(stringValue, dna.Description, StringComparison.Ordinal))
                        {
                            return Enum.Parse(_enumType, fi.Name);
                        }
                    }

                    return Enum.Parse(_enumType, stringValue);
                }

                throw new ArgumentNullException(nameof(value), "Value cannot be null.");
            }
        }

        public class YesNoTypeConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
            {
                return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
            }
            public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
            {
                return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
            }

            public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
            {
                if (value is not string stringValue)
                {
                    // Ensure 'value' is not null before passing it to the base method
                    return value != null
                        ? base.ConvertFrom(context, culture, value)
                        : throw new ArgumentNullException(nameof(value), "Value cannot be null.");
                }

                if (string.Equals(stringValue, Language.Yes, StringComparison.CurrentCultureIgnoreCase))
                {
                    return true;
                }

                if (string.Equals(stringValue, Language.No, StringComparison.CurrentCultureIgnoreCase))
                {
                    return false;
                }

                throw new Exception("Values must be \"Yes\" or \"No\"");
            }

            public override object ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
            {
                if (destinationType == typeof(string))
                {
                    return Convert.ToBoolean(value) ? Language.Yes : Language.No;
                }

                return base.ConvertTo(context, culture, value, destinationType) ?? throw new InvalidOperationException("Base conversion returned null.");
            }

            public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
            {
                return true;
            }

            public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
            {
                bool[] bools = { true, false };

                StandardValuesCollection svc = new(bools);

                return svc;
            }
        }
    }
}