import numpy as np

AUDITOK_PLOT_THEME = {
    "figure": {"facecolor": "#482a36", "alpha": 0.2},
    "plot": {"facecolor": "#282a36"},
    "energy_threshold": {
        "color": "#e31f8f",
        "linestyle": "--",
        "linewidth": 1,
    },
    "signal": {"color": "#40d970", "linestyle": "-", "linewidth": 1},
    "detections": {
        "facecolor": "#777777",
        "edgecolor": "#ff8c1a",
        "linewidth": 1,
        "alpha": 0.75,
    },
}


def _make_time_axis(nb_samples, sampling_rate):
    sample_duration = 1 / sampling_rate
    x = np.linspace(0, sample_duration * (nb_samples - 1), nb_samples)
    return x


def _plot_line(x, y, theme, xlabel=None, ylabel=None, **kwargs):
    import matplotlib.pyplot as plt

    color = theme.get("color", theme.get("c"))
    ls = theme.get("linestyle", theme.get("ls"))
    lw = theme.get("linewidth", theme.get("lw"))
    plt.plot(x, y, c=color, ls=ls, lw=lw, **kwargs)
    plt.xlabel(xlabel, fontsize=8)
    plt.ylabel(ylabel, fontsize=8)


def _plot_detections(subplot, detections, theme):
    fc = theme.get("facecolor", theme.get("fc"))
    ec = theme.get("edgecolor", theme.get("ec"))
    ls = theme.get("linestyle", theme.get("ls"))
    lw = theme.get("linewidth", theme.get("lw"))
    alpha = theme.get("alpha")
    for start, end in detections:
        subplot.axvspan(start, end, fc=fc, ec=ec, ls=ls, lw=lw, alpha=alpha)


def plot(
    audio_region,
    scale_signal=True,
    detections=None,
    energy_threshold=None,
    show=True,
    figsize=None,
    save_as=None,
    dpi=120,
    theme="auditok",
):
    import matplotlib.pyplot as plt

    y = np.asarray(audio_region)
    if len(y.shape) == 1:
        y = y.reshape(1, -1)
    nb_subplots, nb_samples = y.shape
    sampling_rate = audio_region.sampling_rate
    time_axis = _make_time_axis(nb_samples, sampling_rate)
    if energy_threshold is not None:
        eth_log10 = energy_threshold * np.log(10) / 10
        amplitude_threshold = np.sqrt(np.exp(eth_log10))
    else:
        amplitude_threshold = None
    if detections is None:
        detections = []
    else:
        # End of detection corresponds to the end of the last sample but
        # to stay compatible with the time axis of signal plotting we want end
        # of detection to correspond to the *start* of the that last sample.
        detections = [
            (start, end - (1 / sampling_rate)) for (start, end) in detections
        ]
    if figsize is None:
        figsize = (14, 2.5 * nb_subplots)

    if theme == "auditok":
        theme = AUDITOK_PLOT_THEME

    fig = plt.figure(figsize=figsize, dpi=dpi)
    fig_theme = theme.get("figure", theme.get("fig", {}))
    fig_fc = fig_theme.get("facecolor", fig_theme.get("ffc"))
    fig_alpha = fig_theme.get("alpha", 1)
    fig.patch.set_facecolor(fig_fc)
    fig.patch.set_alpha(fig_alpha)

    plot_theme = theme.get("plot", {})
    plot_fc = plot_theme.get("facecolor", plot_theme.get("pfc"))

    if nb_subplots > 2 and nb_subplots % 2 == 0:
        nb_rows = nb_subplots // 2
        nb_columns = 2
    else:
        nb_rows = nb_subplots
        nb_columns = 1

    for sid, samples in enumerate(y, 1):
        ax = fig.add_subplot(nb_rows, nb_columns, sid)
        ax.set_facecolor(plot_fc)
        if scale_signal:
            std = samples.std()
            if std > 0:
                mean = samples.mean()
                std = samples.std()
                samples = (samples - mean) / std
                max_ = samples.max()
                plt.ylim(-1.5 * max_, 1.5 * max_)
        if amplitude_threshold is not None:
            if scale_signal and std > 0:
                amp_th = (amplitude_threshold - mean) / std
            else:
                amp_th = amplitude_threshold
            eth_theme = theme.get("energy_threshold", theme.get("eth", {}))
            _plot_line(
                [time_axis[0], time_axis[-1]],
                [amp_th] * 2,
                eth_theme,
                label="Detection threshold",
            )
            if sid == 1:
                leg = plt.legend(
                    ["Detection threshold"],
                    facecolor=plot_fc,
                    framealpha=1.0,
                    edgecolor="#555555",
                    loc="upper right",
                    fontsize=8,
                )
                for text in leg.get_texts():
                    text.set_color("#cccccc")

        signal_theme = theme.get("signal", {})
        _plot_line(
            time_axis,
            samples,
            signal_theme,
            xlabel="Time (seconds)",
            ylabel="Signal{}".format(" (scaled)" if scale_signal else ""),
        )
        detections_theme = theme.get("detections", {})
        _plot_detections(ax, detections, detections_theme)
        plt.title("Channel {}".format(sid), fontsize=10)

        plt.xticks(fontsize=8)
        plt.yticks(fontsize=8)
    plt.tight_layout()

    if save_as is not None:
        plt.savefig(save_as, dpi=dpi)
    if show:
        plt.show()
