#
# This file is taken from https://github.com/pandas-dev/pandas as suggested by
# the pandas-dev mailing list. The goal is to ask the matplotlib devs to
# eventually incorporate this into matplotlib proper.
#

# being a bit too dynamic
import warnings

import matplotlib.cm as cm
import matplotlib.colors
import numpy as np
import pandas.core.common as com
from pandas.core.dtypes.common import is_list_like


def _get_standard_colors(  # noqa: C901
    num_colors=None, colormap=None, color_type="default", color=None
):
    import matplotlib.pyplot as plt

    if color is None and colormap is not None:
        if isinstance(colormap, str):
            cmap = colormap
            colormap = cm.get_cmap(colormap)
            if colormap is None:
                raise ValueError(f"Colormap {cmap} is not recognized")
        colors = [colormap(num) for num in np.linspace(0, 1, num=num_colors)]
    elif color is not None:
        if colormap is not None:
            warnings.warn(
                "'color' and 'colormap' cannot be used "
                + "simultaneously. Using 'color'"
            )
        colors = list(color) if is_list_like(color) else color
    else:
        if color_type == "default":
            # need to call list() on the result to copy so we don't
            # modify the global rcParams below
            try:
                colors = [c["color"] for c in list(plt.rcParams["axes.prop_cycle"])]
            except KeyError:
                colors = list(plt.rcParams.get("axes.color_cycle", list("bgrcmyk")))
            if isinstance(colors, str):
                colors = list(colors)

            colors = colors[0:num_colors]
        elif color_type == "random":

            def random_color(column):
                """Returns a random color represented as a list of length 3"""
                # GH17525 use common._random_state to avoid resetting the seed
                rs = com.random_state(column)
                return rs.rand(3).tolist()

            colors = [random_color(num) for num in range(num_colors)]
        else:
            raise ValueError("color_type must be either 'default' or 'random'")

    if isinstance(colors, str):
        conv = matplotlib.colors.ColorConverter()

        def _maybe_valid_colors(colors):
            try:
                [conv.to_rgba(c) for c in colors]
                return True
            except ValueError:
                return False

        # check whether the string can be convertible to single color
        maybe_single_color = _maybe_valid_colors([colors])
        # check whether each character can be convertible to colors
        maybe_color_cycle = _maybe_valid_colors(list(colors))
        if maybe_single_color and maybe_color_cycle and len(colors) > 1:
            hex_color = [c["color"] for c in list(plt.rcParams["axes.prop_cycle"])]
            colors = [hex_color[int(colors[1])]]
        elif maybe_single_color:
            colors = [colors]
        else:
            # ``colors`` is regarded as color cycle.
            # mpl will raise error any of them is invalid
            pass

    # Append more colors by cycling if there is not enough color.
    # Extra colors will be ignored by matplotlib if there are more colors
    # than needed and nothing needs to be done here.
    if len(colors) < num_colors:
        try:
            multiple = num_colors // len(colors) - 1
        except ZeroDivisionError:
            raise ValueError("Invalid color argument: ''")
        mod = num_colors % len(colors)

        colors += multiple * colors
        colors += colors[:mod]

    return colors
