using System;
using System.Drawing;
using System.Globalization;

namespace EonaCat.Logger.Helpers
{
    public static class ColorHelper
    {
        public static string ColorToHexString(Color c)
        {
            return "#" + c.R.ToString("X2") + c.G.ToString("X2") + c.B.ToString("X2");
        }

        public static string ColorToRGBString(Color c)
        {
            return "RGB(" + c.R.ToString() + "," + c.G.ToString() + "," + c.B.ToString() + ")";
        }

        public static Color ConsoleColorToColor(this ConsoleColor consoleColor)
        {
            switch (consoleColor)
            {
                case ConsoleColor.Black:
                    return Color.Black;

                case ConsoleColor.DarkBlue:
                    return HexStringToColor("#000080");

                case ConsoleColor.DarkGreen:
                    return HexStringToColor("#008000");

                case ConsoleColor.DarkCyan:
                    return HexStringToColor("#008080");

                case ConsoleColor.DarkRed:
                    return HexStringToColor("#800000");

                case ConsoleColor.DarkMagenta:
                    return HexStringToColor("#800080");

                case ConsoleColor.DarkYellow:
                    return HexStringToColor("#808000");

                case ConsoleColor.Gray:
                    return HexStringToColor("#C0C0C0");

                case ConsoleColor.DarkGray:
                    return HexStringToColor("#808080");

                case ConsoleColor.Blue:
                    return Color.Blue;

                case ConsoleColor.Green:
                    return Color.Lime;

                case ConsoleColor.Cyan:
                    return Color.Cyan;

                case ConsoleColor.Red:
                    return Color.Red;

                case ConsoleColor.Magenta:
                    return Color.Magenta;

                case ConsoleColor.Yellow:
                    return Color.Yellow;

                case ConsoleColor.White:
                    return Color.White;

                default:
                    throw new NotSupportedException();
            }
        }

        public static Color HexStringToColor(string htmlColor, bool requireHexSpecified = false, int defaultAlpha = 0xFF) => Color.FromArgb(HexColorToArgb(htmlColor, requireHexSpecified, defaultAlpha));

        public static int HexColorToArgb(string htmlColor, bool requireHexSpecified = false, int defaultAlpha = 0xFF)
        {
            if (string.IsNullOrEmpty(htmlColor))
            {
                throw new ArgumentNullException(nameof(htmlColor));
            }

            if (!htmlColor.StartsWith("#") && requireHexSpecified)
            {
                throw new ArgumentException($"Provided parameter '{htmlColor}' is not valid");
            }

            htmlColor = htmlColor.TrimStart('#');


            var symbolCount = htmlColor.Length;
            var value = int.Parse(htmlColor, NumberStyles.HexNumber);
            switch (symbolCount)
            {
                case 3: // RGB short hand
                    {
                        return defaultAlpha << 24
                            | value & 0xF
                            | (value & 0xF) << 4
                            | (value & 0xF0) << 4
                            | (value & 0xF0) << 8
                            | (value & 0xF00) << 8
                            | (value & 0xF00) << 12
                            ;
                    }
                case 4: // RGBA short hand
                    {
                        // Inline alpha swap
                        return (value & 0xF) << 24
                               | (value & 0xF) << 28
                               | (value & 0xF0) >> 4
                               | value & 0xF0
                               | value & 0xF00
                               | (value & 0xF00) << 4
                               | (value & 0xF000) << 4
                               | (value & 0xF000) << 8
                               ;
                    }
                case 6: // RGB complete definition
                    {
                        return defaultAlpha << 24 | value;
                    }
                case 8: // RGBA complete definition
                    {
                        // Alpha swap
                        return (value & 0xFF) << 24 | value >> 8;
                    }
                default:
                    throw new FormatException("Invalid HTML Color");
            }
        }
    }
}
