using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// 颜色自动生成帮助类
/// </summary>
public static class ColorHelper
{
    private static readonly Dictionary<string, Color> _colorCache = new Dictionary<string, Color>();//颜色缓存
    private static readonly Dictionary<string, string> _htmlColorCache = new Dictionary<string, string>();//颜色缓存

    /// <summary>
    /// 判断color是否为HtmlColor(HtmlColor格式如#A1B2C3)
    /// </summary>
    /// <param name="color"></param>
    /// <returns></returns>
    public static bool IsHtmlColor(string color)
    {
        if (!color.StartsWith("#")) return false;
        if (color.Length != 7) return false;
        string r = color.Substring(1, 2);
        string g = color.Substring(3, 2);
        string b = color.Substring(5, 2);
        bool r1 = byte.TryParse(r, System.Globalization.NumberStyles.HexNumber, null, out _);
        bool r2 = byte.TryParse(g, System.Globalization.NumberStyles.HexNumber, null, out _);
        bool r3 = byte.TryParse(b, System.Globalization.NumberStyles.HexNumber, null, out _);
        return r1 & r2 & r3;
    }
    /// <summary>
    /// 根据key得到一种易识别的颜色,相同的key会得到相同的颜色(若要使多个key得到的颜色具有高对比度,请先调用GenerateColor)
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static Color GetColor(string key)
    {
        if (key == null) key = "";
        if (_colorCache.ContainsKey(key))
            return _colorCache[key];
        Random random = new Random(key.GetHashCode());
        var H = random.Next(0, 360);//色调
        var S = random.NextDouble();//饱和度
        var L = random.NextDouble();//亮度

        S = 0.7 + S * 0.2; // [0.7 - 0.9] 排除过灰颜色
        L = 0.4 + L * 0.4; // [0.4 - 0.8] 排除过亮过暗色

        byte r, g, b;
        if (S == 0)
        {
            r = g = b = (byte)(L * 255);
        }
        else
        {
            double v1, v2;
            double hue = H / 360d;
            v2 = (L < 0.5) ? (L * (1 + S)) : ((L + S) - (L * S));
            v1 = 2 * L - v2;
            r = (byte)(255 * HueToRGB(v1, v2, hue + (1.0f / 3)));
            g = (byte)(255 * HueToRGB(v1, v2, hue));
            b = (byte)(255 * HueToRGB(v1, v2, hue - (1.0f / 3)));
        }
        var color = Color.FromArgb(r, g, b);
        var rgbhtml = ColorTranslator.ToHtml(color);

        if (!_colorCache.ContainsKey(key))
            _colorCache.Add(key, color);

        if (!_htmlColorCache.ContainsKey(key))
            _htmlColorCache.Add(key, rgbhtml);
        return color;
    }

    /// <summary>
    /// 根据key得到一种易识别的颜色,相同的key会得到相同的颜色(若要使多个key得到的颜色具有高对比度,请先调用GenerateColor)
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static string GetHtmlColor(string key)
    {
        if (key == null) key = "";
        if (_htmlColorCache.ContainsKey(key))
            return _htmlColorCache[key];
        string rgbhtml = ColorTranslator.ToHtml(GetColor(key));
        return rgbhtml;
    }

    /// <summary>
    /// 提前生成多个易识别且不相近的颜色,生成后通过GetColor或CetHtmlColor获取
    /// </summary>
    /// <param name="keys">所有颜色对应的key,个数超过360时效果不佳</param>
    /// <returns></returns>
    public static void GenerateColor(IEnumerable<string> keys)
    {
        _colorCache.Clear();
        _htmlColorCache.Clear();
        keys = keys.Distinct();
        int idx = 0;
        List<(int H, double S, double L)> list = new List<(int H, double S, double L)>();
        int count = keys.Count();
        int value = 360 / count;
        if (value == 0) value = 1;
        foreach (var key in keys)
        {
            Random random = new Random(key.GetHashCode());
            int H = random.Next(idx * value, (idx + 1) * value);//色调
            H %= 360;
            double S = random.NextDouble();//饱和度
            double L = random.NextDouble();//亮度
            S = 0.7 + S * 0.2; // [0.7 - 0.9] 排除过灰颜色
            L = 0.4 + L * 0.4; // [0.4 - 0.8] 排除过亮过暗色
            byte r, g, b;
            if (S == 0)
            {
                r = g = b = (byte)(L * 255);
            }
            else
            {
                double v1, v2;
                double hue = H / 360d;
                v2 = (L < 0.5) ? (L * (1 + S)) : ((L + S) - (L * S));
                v1 = 2 * L - v2;
                r = (byte)(255 * HueToRGB(v1, v2, hue + (1.0f / 3)));
                g = (byte)(255 * HueToRGB(v1, v2, hue));
                b = (byte)(255 * HueToRGB(v1, v2, hue - (1.0f / 3)));
            }
            list.Add((H, S, L));
            var color = Color.FromArgb(r, g, b);
            var rgbhtml = ColorTranslator.ToHtml(color);
            if (!_colorCache.ContainsKey(key))
                _colorCache.Add(key, color);
            else
                _colorCache[key] = color;

            if (!_htmlColorCache.ContainsKey(key))
                _htmlColorCache.Add(key, rgbhtml);
            else
                _htmlColorCache[key] = rgbhtml;
            idx++;
        }
    }


    private static double HueToRGB(double v1, double v2, double vH)
    {
        if (vH < 0)
            vH += 1;

        if (vH > 1)
            vH -= 1;

        if ((6 * vH) < 1)
            return (v1 + (v2 - v1) * 6 * vH);

        if ((2 * vH) < 1)
            return v2;

        if ((3 * vH) < 2)
            return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);

        return v1;
    }

}
