module TableTennis
  module Util
    # Named color names and misc color helpers.
    module Colors
      prepend MemoWise

      module_function

      NAMED = {
        #
        # css colors
        # https://htmlcolorcodes.com/color-names/
        #

        # red
        "indianred" => "#cd5c5c",
        "lightcoral" => "#f08080",
        "salmon" => "#fa8072",
        "darksalmon" => "#e9967a",
        "lightsalmon" => "#ffa07a",
        "crimson" => "#dc143c",
        "red" => "#ff0000",
        "firebrick" => "#b22222",
        "darkred" => "#8b0000",
        # pink
        "pink" => "#ffc0cb",
        "lightpink" => "#ffb6c1",
        "hotpink" => "#ff69b4",
        "deeppink" => "#ff1493",
        "mediumvioletred" => "#c71585",
        "palevioletred" => "#db7093",
        # orange
        # "lightsalmon" => "#ffa07a",
        "coral" => "#ff7f50",
        "tomato" => "#ff6347",
        "orangered" => "#ff4500",
        "darkorange" => "#ff8c00",
        "orange" => "#ffa500",
        # gold
        "gold" => "#ffd700",
        "yellow" => "#ffff00",
        "lightyellow" => "#ffffe0",
        "lemonchiffon" => "#fffacd",
        "lightgoldenrodyellow" => "#fafad2",
        "papayawhip" => "#ffefd5",
        "moccasin" => "#ffe4b5",
        "peachpuff" => "#ffdab9",
        "palegoldenrod" => "#eee8aa",
        "khaki" => "#f0e68c",
        "darkkhaki" => "#bdb76b",
        # purple
        "lavender" => "#e6e6fa",
        "thistle" => "#d8bfd8",
        "plum" => "#dda0dd",
        "violet" => "#ee82ee",
        "orchid" => "#da70d6",
        "fuchsia" => "#ff00ff",
        "magenta" => "#ff00ff",
        "mediumorchid" => "#ba55d3",
        "mediumpurple" => "#9370db",
        "rebeccapurple" => "#663399",
        "blueviolet" => "#8a2be2",
        "darkviolet" => "#9400d3",
        "darkorchid" => "#9932cc",
        "darkmagenta" => "#8b008b",
        "purple" => "#800080",
        "indigo" => "#4b0082",
        "slateblue" => "#6a5acd",
        "darkslateblue" => "#483d8b",
        # "mediumslateblue" => "#7b68ee",
        # green
        "greenyellow" => "#adff2f",
        "chartreuse" => "#7fff00",
        "lawngreen" => "#7cfc00",
        "lime" => "#00ff00",
        "limegreen" => "#32cd32",
        "palegreen" => "#98fb98",
        "lightgreen" => "#90ee90",
        "mediumspringgreen" => "#00fa9a",
        "springgreen" => "#00ff7f",
        "mediumseagreen" => "#3cb371",
        "seagreen" => "#2e8b57",
        "forestgreen" => "#228b22",
        "green" => "#008000",
        "darkgreen" => "#006400",
        "yellowgreen" => "#9acd32",
        "olivedrab" => "#6b8e23",
        "olive" => "#808000",
        "darkolivegreen" => "#556b2f",
        "mediumaquamarine" => "#66cdaa",
        "darkseagreen" => "#8fbc8b",
        "lightseagreen" => "#20b2aa",
        "darkcyan" => "#008b8b",
        "teal" => "#008080",
        # blue
        "aqua" => "#00ffff",
        "cyan" => "#00ffff",
        "lightcyan" => "#e0ffff",
        "paleturquoise" => "#afeeee",
        "aquamarine" => "#7fffd4",
        "turquoise" => "#40e0d0",
        "mediumturquoise" => "#48d1cc",
        "darkturquoise" => "#00ced1",
        "cadetblue" => "#5f9ea0",
        "steelblue" => "#4682b4",
        "lightsteelblue" => "#b0c4de",
        "powderblue" => "#b0e0e6",
        "lightblue" => "#add8e6",
        "skyblue" => "#87ceeb",
        "lightskyblue" => "#87cefa",
        "deepskyblue" => "#00bfff",
        "dodgerblue" => "#1e90ff",
        "cornflowerblue" => "#6495ed",
        "mediumslateblue" => "#7b68ee",
        "royalblue" => "#4169e1",
        "blue" => "#0000ff",
        "mediumblue" => "#0000cd",
        "darkblue" => "#00008b",
        "navy" => "#000080",
        "midnightblue" => "#191970",
        # brown
        "cornsilk" => "#fff8dc",
        "blanchedalmond" => "#ffebcd",
        "bisque" => "#ffe4c4",
        "navajowhite" => "#ffdead",
        "wheat" => "#f5deb3",
        "burlywood" => "#deb887",
        "tan" => "#d2b48c",
        "rosybrown" => "#bc8f8f",
        "sandybrown" => "#f4a460",
        "goldenrod" => "#daa520",
        "darkgoldenrod" => "#b8860b",
        "peru" => "#cd853f",
        "chocolate" => "#d2691e",
        "saddlebrown" => "#8b4513",
        "sienna" => "#a0522d",
        "brown" => "#a52a2a",
        "maroon" => "#800000",
        # white
        "white" => "#ffffff",
        "snow" => "#fffafa",
        "honeydew" => "#f0fff0",
        "mintcream" => "#f5fffa",
        "azure" => "#f0ffff",
        "aliceblue" => "#f0f8ff",
        "ghostwhite" => "#f8f8ff",
        "whitesmoke" => "#f5f5f5",
        "seashell" => "#fff5ee",
        "beige" => "#f5f5dc",
        "oldlace" => "#fdf5e6",
        "floralwhite" => "#fffaf0",
        "ivory" => "#fffff0",
        "antiquewhite" => "#faebd7",
        "linen" => "#faf0e6",
        "lavenderblush" => "#fff0f5",
        "mistyrose" => "#ffe4e1",
        # gray
        "gainsboro" => "#dcdcdc",
        "lightgray" => "#d3d3d3",
        "silver" => "#c0c0c0",
        "darkgray" => "#a9a9a9",
        "gray" => "#808080",
        "dimgray" => "#696969",
        "lightslategray" => "#778899",
        "slategray" => "#708090",
        "darkslategray" => "#2f4f4f",
        "black" => "#000000",

        #
        # tailwind
        #

        "slate-50" => "#f8fafc",
        "slate-100" => "#f1f5f9",
        "slate-200" => "#e2e8f0",
        "slate-300" => "#cbd5e1",
        "slate-400" => "#94a3b8",
        "slate-500" => "#64748b",
        "slate-600" => "#475569",
        "slate-700" => "#334155",
        "slate-800" => "#1e293b",
        "slate-900" => "#0f172a",
        "gray-50" => "#f9fafb",
        "gray-100" => "#f3f4f6",
        "gray-200" => "#e5e7eb",
        "gray-300" => "#d1d5db",
        "gray-400" => "#9ca3af",
        "gray-500" => "#6b7280",
        "gray-600" => "#4b5563",
        "gray-700" => "#374151",
        "gray-800" => "#1f2937",
        "gray-900" => "#111827",
        "zinc-50" => "#fafafa",
        "zinc-100" => "#f4f4f5",
        "zinc-200" => "#e4e4e7",
        "zinc-300" => "#d4d4d8",
        "zinc-400" => "#a1a1aa",
        "zinc-500" => "#71717a",
        "zinc-600" => "#52525b",
        "zinc-700" => "#3f3f46",
        "zinc-800" => "#27272a",
        "zinc-900" => "#18181b",
        "neutral-50" => "#fafafa",
        "neutral-100" => "#f5f5f5",
        "neutral-200" => "#e5e5e5",
        "neutral-300" => "#d4d4d4",
        "neutral-400" => "#a3a3a3",
        "neutral-500" => "#737373",
        "neutral-600" => "#525252",
        "neutral-700" => "#404040",
        "neutral-800" => "#262626",
        "neutral-900" => "#171717",
        "stone-50" => "#fafaf9",
        "stone-100" => "#f5f5f4",
        "stone-200" => "#e7e5e4",
        "stone-300" => "#d6d3d1",
        "stone-400" => "#a8a29e",
        "stone-500" => "#78716c",
        "stone-600" => "#57534e",
        "stone-700" => "#44403c",
        "stone-800" => "#292524",
        "stone-900" => "#1c1917",
        "red-50" => "#fef2f2",
        "red-100" => "#fee2e2",
        "red-200" => "#fecaca",
        "red-300" => "#fca5a5",
        "red-400" => "#f87171",
        "red-500" => "#ef4444",
        "red-600" => "#dc2626",
        "red-700" => "#b91c1c",
        "red-800" => "#991b1b",
        "red-900" => "#7f1d1d",
        "orange-50" => "#fff7ed",
        "orange-100" => "#ffedd5",
        "orange-200" => "#fed7aa",
        "orange-300" => "#fdba74",
        "orange-400" => "#fb923c",
        "orange-500" => "#f97316",
        "orange-600" => "#ea580c",
        "orange-700" => "#c2410c",
        "orange-800" => "#9a3412",
        "orange-900" => "#7c2d12",
        "amber-50" => "#fffbeb",
        "amber-100" => "#fef3c7",
        "amber-200" => "#fde68a",
        "amber-300" => "#fcd34d",
        "amber-400" => "#fbbf24",
        "amber-500" => "#f59e0b",
        "amber-600" => "#d97706",
        "amber-700" => "#b45309",
        "amber-800" => "#92400e",
        "amber-900" => "#78350f",
        "yellow-50" => "#fefce8",
        "yellow-100" => "#fef9c3",
        "yellow-200" => "#fef08a",
        "yellow-300" => "#fde047",
        "yellow-400" => "#facc15",
        "yellow-500" => "#eab308",
        "yellow-600" => "#ca8a04",
        "yellow-700" => "#a16207",
        "yellow-800" => "#854d0e",
        "yellow-900" => "#713f12",
        "lime-50" => "#f7fee7",
        "lime-100" => "#ecfccb",
        "lime-200" => "#d9f99d",
        "lime-300" => "#bef264",
        "lime-400" => "#a3e635",
        "lime-500" => "#84cc16",
        "lime-600" => "#65a30d",
        "lime-700" => "#4d7c0f",
        "lime-800" => "#3f6212",
        "lime-900" => "#365314",
        "green-50" => "#f0fdf4",
        "green-100" => "#dcfce7",
        "green-200" => "#bbf7d0",
        "green-300" => "#86efac",
        "green-400" => "#4ade80",
        "green-500" => "#22c55e",
        "green-600" => "#16a34a",
        "green-700" => "#15803d",
        "green-800" => "#166534",
        "green-900" => "#14532d",
        "emerald-50" => "#ecfdf5",
        "emerald-100" => "#d1fae5",
        "emerald-200" => "#a7f3d0",
        "emerald-300" => "#6ee7b7",
        "emerald-400" => "#34d399",
        "emerald-500" => "#10b981",
        "emerald-600" => "#059669",
        "emerald-700" => "#047857",
        "emerald-800" => "#065f46",
        "emerald-900" => "#064e3b",
        "teal-50" => "#f0fdfa",
        "teal-100" => "#ccfbf1",
        "teal-200" => "#99f6e4",
        "teal-300" => "#5eead4",
        "teal-400" => "#2dd4bf",
        "teal-500" => "#14b8a6",
        "teal-600" => "#0d9488",
        "teal-700" => "#0f766e",
        "teal-800" => "#115e59",
        "teal-900" => "#134e4a",
        "cyan-50" => "#ecfeff",
        "cyan-100" => "#cffafe",
        "cyan-200" => "#a5f3fc",
        "cyan-300" => "#67e8f9",
        "cyan-400" => "#22d3ee",
        "cyan-500" => "#06b6d4",
        "cyan-600" => "#0891b2",
        "cyan-700" => "#0e7490",
        "cyan-800" => "#155e75",
        "cyan-900" => "#164e63",
        "sky-50" => "#f0f9ff",
        "sky-100" => "#e0f2fe",
        "sky-200" => "#bae6fd",
        "sky-300" => "#7dd3fc",
        "sky-400" => "#38bdf8",
        "sky-500" => "#0ea5e9",
        "sky-600" => "#0284c7",
        "sky-700" => "#0369a1",
        "sky-800" => "#075985",
        "sky-900" => "#0c4a6e",
        "blue-50" => "#eff6ff",
        "blue-100" => "#dbeafe",
        "blue-200" => "#bfdbfe",
        "blue-300" => "#93c5fd",
        "blue-400" => "#60a5fa",
        "blue-500" => "#3b82f6",
        "blue-600" => "#2563eb",
        "blue-700" => "#1d4ed8",
        "blue-800" => "#1e40af",
        "blue-900" => "#1e3a8a",
        "indigo-50" => "#eef2ff",
        "indigo-100" => "#e0e7ff",
        "indigo-200" => "#c7d2fe",
        "indigo-300" => "#a5b4fc",
        "indigo-400" => "#818cf8",
        "indigo-500" => "#6366f1",
        "indigo-600" => "#4f46e5",
        "indigo-700" => "#4338ca",
        "indigo-800" => "#3730a3",
        "indigo-900" => "#312e81",
        "violet-50" => "#f5f3ff",
        "violet-100" => "#ede9fe",
        "violet-200" => "#ddd6fe",
        "violet-300" => "#c4b5fd",
        "violet-400" => "#a78bfa",
        "violet-500" => "#8b5cf6",
        "violet-600" => "#7c3aed",
        "violet-700" => "#6d28d9",
        "violet-800" => "#5b21b6",
        "violet-900" => "#4c1d95",
        "purple-50" => "#faf5ff",
        "purple-100" => "#f3e8ff",
        "purple-200" => "#e9d5ff",
        "purple-300" => "#d8b4fe",
        "purple-400" => "#c084fc",
        "purple-500" => "#a855f7",
        "purple-600" => "#9333ea",
        "purple-700" => "#7e22ce",
        "purple-800" => "#6b21a8",
        "purple-900" => "#581c87",
        "fuchsia-50" => "#fdf4ff",
        "fuchsia-100" => "#fae8ff",
        "fuchsia-200" => "#f5d0fe",
        "fuchsia-300" => "#f0abfc",
        "fuchsia-400" => "#e879f9",
        "fuchsia-500" => "#d946ef",
        "fuchsia-600" => "#c026d3",
        "fuchsia-700" => "#a21caf",
        "fuchsia-800" => "#86198f",
        "fuchsia-900" => "#701a75",
        "pink-50" => "#fdf2f8",
        "pink-100" => "#fce7f3",
        "pink-200" => "#fbcfe8",
        "pink-300" => "#f9a8d4",
        "pink-400" => "#f472b6",
        "pink-500" => "#ec4899",
        "pink-600" => "#db2777",
        "pink-700" => "#be185d",
        "pink-800" => "#9d174d",
        "pink-900" => "#831843",
        "rose-50" => "#fff1f2",
        "rose-100" => "#ffe4e6",
        "rose-200" => "#fecdd3",
        "rose-300" => "#fda4af",
        "rose-400" => "#fb7185",
        "rose-500" => "#f43f5e",
        "rose-600" => "#e11d48",
        "rose-700" => "#be123c",
        "rose-800" => "#9f1239",
        "rose-900" => "#881337",
      }

      SYMBOLS = (Paint::ANSI_COLORS.keys + Paint::ANSI_EFFECTS.keys).to_set

      # we support a few different kinds of colors
      def get(color)
        case color
        # nil is ok
        when nil
          return nil

        # hex string
        when /^#?[0-9a-f]{3}([0-9a-f]{3})?$/i
          return color

        when Symbol
          # Paint ansi color or ansi effect
          if !SYMBOLS.include?(color)
            puts "warning: TableTennis #{color.inspect} unknown ansi color/effect symbol"
            return
          end
          return color

        when String
          if !(hex = NAMED[color.downcase])
            puts "warning: TableTennis #{color.inspect} unknown named color string"
            return
          end
          return hex

        else
          puts "warning: TableTennis #{color.inspect} unknown color"
          return
        end
      end

      # sRGB to Y (relative luminance)
      def luma(hex)
        rgb = to_rgb(hex)
        return if !rgb
        rgb = rgb.map { _1 / 255.0 }
        coeff = [0.2126, 0.7152, 0.0722]
        rgb.zip(coeff).sum { (_1**2.2) * _2 }.round(3)
      end

      DARK_LUMA = 0.36

      # is this color dark?
      def dark?(color)
        color = get(color)
        return true if !color

        # take a guess at symbols too
        if color.is_a?(Symbol)
          return !%i[white gray].include?(color)
        end

        luma = luma(color)
        !luma || luma < DARK_LUMA
      end

      def contrast(bg)
        dark?(bg) ? "white" : "black"
      end
      memo_wise self: :contrast

      # [r,g,b] => "#rrggbb"
      def to_hex(rgb)
        sprintf("#%02x%02x%02x", *rgb)
      end

      # "#?(rgb|rrggbb|rrrrggggbbbb)" => [r,g,b]
      def to_rgb(hex)
        if !hex.match(/\A#?([0-9a-f]+)\Z/i)
          return
        end
        hex = $1
        case hex.length
        when 3 then hex.scan(/./).map { "#{_1}#{_1}" }
        when 6 then hex.scan(/../)
        when 9 then hex.scan(/.../)
        when 12 then hex.scan(/..../)
        else; return
        end.map { _1[0, 2].to_i(16) }
      end

      # lookup RGB for an ansi fg or bg color
      def ansi_color_to_hex(num)
        return if !(0..15).cover?(num)
        rgb = if num < 8
          Paint::RGB_COLORS_ANSI.values[num]
        else
          Paint::RGB_COLORS_ANSI_BRIGHT.values[num - 8]
        end
        to_hex(rgb)
      end

      # print all colors to $stdout, helps with creating themes
      def spectrum
        max = NAMED.keys.map(&:length).max
        fmt = " %-#{max}s %s  %0.3f "
        NAMED.each do |name, color|
          str = sprintf(fmt, name, color, luma(color))
          str1 = Paint[str, color, "white"]
          str2 = Paint[str, color, "black"]
          str3 = Paint["  white   ", "white", color]
          str4 = Paint[" black  ", "black", color]
          puts "#{str1}#{str2}#{str3}#{str4}"
        end

        fmt = " ansi %-6s %-8s "
        colors = Paint::ANSI_COLORS_FOREGROUND.keys
        puts
        colors.each do
          fg = sprintf(fmt, "normal", _1.inspect)
          str1 = Paint[fg, _1, :white]
          str2 = Paint[fg, _1, :black]
          puts "#{str1}#{str2}"
        end
        puts
        colors.each do
          str = sprintf(fmt, ":bold", _1.inspect)
          str1 = Paint[str, _1, :bold, :white]
          str2 = Paint[str, _1, :bold, :black]
          puts "#{str1}#{str2}"
        end
        puts
        colors.each do
          str = sprintf(fmt, ":faint", _1.inspect)
          str1 = Paint[str, _1, :faint, :white]
          str2 = Paint[str, _1, :faint, :black]
          puts "#{str1}#{str2}"
        end
        puts
        colors.each do
          str1 = Paint[sprintf(" :white on %-8s ", _1.inspect), :white, _1]
          str2 = Paint[sprintf("  :black on %-8s ", _1.inspect), :black, _1]
          puts "#{str1}#{str2}"
        end
      end
    end
  end
end
