{% import (
	"net/url"
	"strconv"
	"strings"

	"github.com/VictoriaMetrics/VictoriaMetrics/lib/htmlcomponents"
	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
) %}

{% stripspace %}

{% func TargetsResponsePlain(tsr *targetsStatusResult, filter *requestFilter) %}

{% if tsr.err != nil %}
	{%s= tsr.err.Error() %}
	{% return %}
{% endif %}

{% for _, jts := range tsr.jobTargetsStatuses %}
	job={%s= jts.jobName %}{% space %}({%d jts.upCount %}/{%d jts.targetsTotal %}{% space %}up)
	{% newline %}
	{% for _, ts := range jts.targetsStatus %}
		{%s= "\t" %}
		state={% if ts.up %}up{% else %}down{% endif %},{% space %}
		endpoint={%s= ts.sw.Config.ScrapeURL %},{% space %}
		labels={%s= ts.sw.Config.Labels.String() %},{% space %}
		{% if filter.showOriginalLabels %}originalLabels={%s= ts.sw.Config.OriginalLabels.String() %},{% space %}{% endif %}
		scrapes_total={%d ts.scrapesTotal %},{% space %}
		scrapes_failed={%d ts.scrapesFailed %},{% space %}
		last_scrape={%s ts.getDurationFromLastScrape() %},{% space %}
		scrape_duration={%d int(ts.scrapeDuration) %}ms,{% space %}
                scrape_response_size={%s ts.getSizeFromLastScrape() %},{% space %}
		samples_scraped={%d ts.samplesScraped %},{% space %}
		error={% if ts.err != nil %}{%s= ts.err.Error() %}{% endif %}
		{% newline %}
	{% endfor %}
{% endfor %}

{% for _, jobName := range tsr.emptyJobs %}
	job={%s= jobName %}{% space %}(0/0 up)
{% newline %}
{% endfor %}

{% endfunc %}

{% func TargetsResponseHTML(tsr *targetsStatusResult, filter *requestFilter) %}
<!DOCTYPE html>
<html lang="en">
<head>
    {%= htmlcomponents.CommonHeader() %}
    <title>Active Targets</title>
</head>
<body>
    {%= htmlcomponents.Navbar() %}
    <div class="container-fluid">
        {% if tsr.err != nil %}
            {%= htmlcomponents.ErrorNotification(tsr.err) %}
        {% endif %}
        <div class="row">
            <main class="col-12">
                <h1>Active Targets</h1>
                <hr />
                {%= filtersForm(filter) %}
                <hr />
                {%= targetsTabs(tsr, filter, "scrapeTargets") %}
            </main>
        </div>
    </div>
</body>
</html>
{% endfunc %}

{% func ServiceDiscoveryResponse(tsr *targetsStatusResult, filter *requestFilter) %}
<!DOCTYPE html>
<html lang="en">
<head>
    {%= htmlcomponents.CommonHeader() %}
    <title>Discovered Targets</title>
</head>
<body>
    {%= htmlcomponents.Navbar() %}
    <div class="container-fluid">
        {% if tsr.err != nil %}
            {%= htmlcomponents.ErrorNotification(tsr.err) %}
        {% endif %}
        <div class="row">
            <main class="col-12">
                <h1>Discovered Targets</h1>
                <hr />
                {%= filtersForm(filter) %}
                <hr />
		{%= targetsTabs(tsr, filter, "discoveredTargets") %}
            </main>
        </div>
    </div>
</body>
</html>
{% endfunc %}

{% func filtersForm(filter *requestFilter) %}
    <div class="row g-3 align-items-center mb-3">
        <div class="col-auto">
            <button id="all-btn" type="button" class="btn{% space %}{% if !filter.showOnlyUnhealthy %}btn-secondary{% else %}btn-success{% endif %}"
              onclick="location.href='?{%= queryArgs(filter, map[string]string{"show_only_unhealthy": "false"}) %}'">
                All
            </button>
        </div>
        <div class="col-auto">
            <button id="unhealthy-btn" type="button" class="btn{% space %}{% if filter.showOnlyUnhealthy %}btn-secondary{% else %}btn-danger{% endif %}"
              onclick="location.href='?{%= queryArgs(filter, map[string]string{"show_only_unhealthy": "true"}) %}'">
                Unhealthy
            </button>
        </div>
        <div class="col-auto">
            <button type="button" class="btn btn-primary" onclick="document.querySelectorAll('.scrape-job').forEach((el) => { el.style.display = 'none'; })">
                Collapse all
            </button>
        </div>
        <div class="col-auto">
            <button type="button" class="btn btn-secondary" onclick="document.querySelectorAll('.scrape-job').forEach((el) => { el.style.display = 'block'; })">
                Expand all
            </button>
        </div>
        <div class="col-auto">
            <button type="button" class="btn btn-success" onclick="document.getElementById('filters').style.display='block'">
                Filter targets
            </button>
        </div>
    </div>
    <div id="filters" {% if filter.endpointSearch == "" && filter.labelSearch == "" %}style="display:none"{% endif %}>
        <form class="form-horizontal">
            <div class="form-group mb-3">
                <label for="endpoint_search" class="col-sm-10 control-label">Endpoint filter (<a target="_blank" href="https://github.com/google/re2/wiki/Syntax">Regexp</a> is accepted)</label>
                <div class="col-sm-10">
                    <input type="text" id="endpoint_search" name="endpoint_search"
                      placeholder="For example, 127.0.0.1" class="form-control" value="{%s filter.endpointSearch %}"/>
                </div>
            </div>
            <div class="form-group mb-3">
                <label for="label_search" class="col-sm-10 control-label">Labels filter (<a target="_blank" href="https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors">Arbitrary time series selectors</a> are accepted)</label>
                <div class="col-sm-10">
                    <input type="text" id="label_search" name="label_search"
                      placeholder="For example, {instance=~'.+:9100'}" class="form-control" value="{%s filter.labelSearch %}"/>
                </div>
            </div>
            <input type="hidden" name="show_only_unhealthy" value="{%v filter.showOnlyUnhealthy %}"/>
            <input type="hidden" name="show_original_labels" value="{%v filter.showOriginalLabels %}"/>
            <button type="submit" class="btn btn-success mb-3">Submit</button>
            <button type="button" class="btn btn-danger mb-3" onclick="location.href='?'">Clear target filters</button>
        </form>
    </div>
{% endfunc %}

{% func targetsTabs(tsr *targetsStatusResult, filter *requestFilter, activeTab string) %}
    <ul class="nav nav-tabs" id="myTab" role="tablist">
        <li class="nav-item" role="presentation">
            <button class="nav-link{%if activeTab=="scrapeTargets"%}{% space %}active{%endif%}" type="button" role="tab"
              onclick="location.href='targets?{%= queryArgs(filter, nil) %}'">
                Active targets
            </button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link{%if activeTab=="discoveredTargets"%}{% space %}active{%endif%}" type="button" role="tab"
              onclick="location.href='service-discovery?{%= queryArgs(filter, nil) %}'">
                Discovered targets
            </button>
        </li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" role="tabpanel">
            {% switch activeTab %}
            {% case "scrapeTargets" %}
                {%= scrapeTargets(tsr) %}
            {% case "discoveredTargets" %}
                {%= discoveredTargets(tsr) %}
            {% endswitch %}
        </div>
    </div>
{% endfunc %}

{% func scrapeTargets(tsr *targetsStatusResult) %}
    <div class="row mt-4">
        <div class="col-12">
            {% for i, jts := range tsr.jobTargetsStatuses %}
                {%= scrapeJobTargets(i, jts, tsr.hasOriginalLabels) %}
            {% endfor %}
            {% for i, jobName := range tsr.emptyJobs %}
                {% code
                    num := i + len(tsr.jobTargetsStatuses)
                    jts := &jobTargetsStatuses{
                        jobName: jobName,
                    }
                %}
                {%= scrapeJobTargets(num, jts, tsr.hasOriginalLabels) %}
            {% endfor %}
        </div>
   </div>
{% endfunc %}

{% func scrapeJobTargets(num int, jts *jobTargetsStatuses, hasOriginalLabels bool) %}
    <div class="row mb-4">
        <div class="col-12">
            <h4>
                <span class="me-2">{%s jts.jobName %}{% space %}({%d jts.upCount %}/{%d jts.targetsTotal %}{% space %}up)</span>
                {%= showHideScrapeJobButtons(num) %}
            </h4>
            <div id="scrape-job-{%d num %}" class="scrape-job table-responsive">
                <table class="table table-striped table-hover table-bordered table-sm">
                    <thead>
                        <tr>
                            <th scope="col">Endpoint</th>
                            <th scope="col">State</th>
                            <th scope="col" title="target labels">Labels</th>
                            {% if hasOriginalLabels %}
                              <th scope="col" title="debug relabeling">Debug relabeling</th>
                            {% endif %}
                            <th scope="col" title="total scrapes">Scrapes</th>
                            <th scope="col" title="total scrape errors">Errors</th>
                            <th scope="col" title="the time of the last scrape">Last Scrape</th>
                            <th scope="col" title="the duration of the last scrape">Duration</th>
                            <th scope="col" title="the size of the last scrape">Last Scrape Size</th>
                            <th scope="col" title="the number of metrics scraped during the last scrape">Samples</th>
                            <th scope="col" title="error from the last scrape (if any)">Last error</th>
                        </tr>
                    </thead>
                    <tbody>
                    {% for _, ts := range jts.targetsStatus %}
                    {% code
                        endpoint := ts.sw.Config.ScrapeURL
                        originalLabels := ts.sw.Config.OriginalLabels

                        // The target is uniquely identified by a pointer to its original labels.
                        targetID := getLabelsID(originalLabels)
                    %}
                        <tr {% if !ts.up %}{%space%}class="alert alert-danger" role="alert" {% endif %}>
                            <td class="endpoint">
                              <a href="{%s endpoint %}" target="_blank">{%s endpoint %}</a>
                                {% if hasOriginalLabels %}
                                  {% space %}
                                  (<a href="target_response?id={%s targetID %}" target="_blank"
                                    title="click to fetch target response on behalf of the scraper">response</a>)
                                {% endif %}
                            </td>
                            <td>
                                {% if ts.up %}
                                    <span class="badge bg-success">UP</span>
                                {% else %}
                                    <span class="badge bg-danger">DOWN</span>
                                {% endif %}
                            </td>
                            <td class="labels">
                              <div
                                {% if hasOriginalLabels %}
                                  {% space %}title="click to show original labels"
                                    onclick="document.getElementById('original-labels-{%s targetID %}').style.display='block'"
                                {% endif %}
                              >
                                {%= formatLabels(ts.sw.Config.Labels) %}
                              </div>
                              {% if hasOriginalLabels %}
                                <div style="display:none" id="original-labels-{%s targetID %}">
                                  {%= formatLabels(originalLabels) %}
                                </div>
                              {% endif %}
                            </td>
                            {% if hasOriginalLabels %}
                              <td>
                                <a href="target-relabel-debug?id={%s targetID %}" target="_blank">target</a>{% space %}
                                <a href="metric-relabel-debug?id={%s targetID %}" target="_blank">metrics</a>
                              </td>
                            {% endif %}
                            <td>{%d ts.scrapesTotal %}</td>
                            <td>{%d ts.scrapesFailed %}</td>
                            <td>{%s ts.getDurationFromLastScrape() %}</td>
                            <td>{%d int(ts.scrapeDuration) %}ms</td>
                            <td>{%s ts.getSizeFromLastScrape() %}</td>
                            <td>{%d ts.samplesScraped %}</td>
                            <td>{% if ts.err != nil %}{%s ts.err.Error() %}{% endif %}</td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endfunc %}

{% func discoveredTargets(tsr *targetsStatusResult) %}
    {% if !tsr.hasOriginalLabels %}
        <div class="alert alert-warning" role="alert">
            Discovered targets are unavailable when <b>-promscrape.dropOriginalLabels</b> command-line flag is set
        </div>
        {% return %}
    {% endif %}

    {% if n := droppedTargetsMap.getTotalTargets(); n > *maxDroppedTargets %}
        <div class="alert alert-warning" role="alert">
            Dropped targets' list below is incomplete, because the number of dropped targets exceeds <b>-promscrape.maxDroppedTargets={%d *maxDroppedTargets %}</b>.<br/>
            If you want to see the full list of dropped targets, then increase <b>-promscrape.maxDroppedTargets</b> command-line flag value to at least{% space %}<b>{%d n %}</b>.<br/>
            Note that this may increase memory usage.
        </div>
    {% endif %}

    {% code tljs := tsr.getTargetLabelsByJob() %}
    <div class="row mt-4">
        <div class="col-12">
            {% for i, tlj := range tljs %}
                {%= discoveredJobTargets(i, tlj) %}
            {% endfor %}
        </div>
    </div>
{% endfunc %}

{% func discoveredJobTargets(num int, tlj *targetLabelsByJob) %}
    <h4>
        <span class="me-2">{%s tlj.jobName %}{% space %}({%d tlj.activeTargets %}/{%d tlj.activeTargets+tlj.droppedTargets %}{% space %}active)</span>
        {%= showHideScrapeJobButtons(num) %}
    </h4>
    <div id="scrape-job-{%d num %}" class="scrape-job table-responsive">
        <table class="table table-striped table-hover table-bordered table-sm">
            <thead>
                <tr>
                    <th scope="col" style="width: 5%">Status</th>
                    <th scope="col" style="width: 60%">Discovered Labels</th>
                    <th scope="col" style="width: 30%">Target Labels</th>
                    <th scope="col" stile="width: 5%">Debug relabeling</a>
                </tr>
            </thead>
            <tbody>
            {% for _, t := range tlj.targets %}
                <tr
                    {% if !t.up %}
                        {% space %}role="alert"{% space %}
                        {% if t.labels.Len() > 0 %}
                            class="alert alert-danger"
                        {% else %}
                            class="alert alert-warning"
                        {% endif %}
                    {% endif %}
                >
                    <td>
                        {% if t.up %}
                            <span class="badge bg-success">UP</span>
                        {% elseif t.labels.Len() > 0 %}
                            <span class="badge bg-danger">DOWN</span>
                        {% else %}
                            <span class="badge bg-warning">DROPPED ({%s string(t.dropReason) %})</span>
                            {% if len(t.clusterMemberNums) > 0 %}
                                <br/>
                                <span title="The target exists at vmagent instances with the given -promscrape.cluster.memberNum values">
                                exists at{% space %}
                                {% for i, memberNum := range t.clusterMemberNums %}
                                    {% if *clusterMemberURLTemplate == "" %}
                                        shard-{%d memberNum %}
                                    {% else %}
                                        <a href="{%s strings.ReplaceAll(*clusterMemberURLTemplate, "%d", strconv.Itoa(memberNum)) %}" target="_blank">shard-{%d memberNum %}</a>
                                    {% endif %}
                                    {% if i+1 < len(t.clusterMemberNums) %},{% space %}{% endif %}
                                {% endfor %}
                            {% endif %}
                        {% endif %}
                    </td>
                    <td class="labels">
                        {%= formatLabels(t.originalLabels) %}
                    </td>
                    <td class="labels">
                        {%= formatLabels(t.labels) %}
                    </td>
                    <td>
                        {% code targetID := getLabelsID(t.originalLabels) %}
                        <a href="target-relabel-debug?id={%s targetID %}" target="_blank">debug</a>
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
{% endfunc %}

{% func showHideScrapeJobButtons(num int) %}
    <button type="button" class="btn btn-primary btn-sm me-1"
      onclick="document.getElementById('scrape-job-{%d num %}').style.display='none'">
        collapse
    </button>
    <button type="button" class="btn btn-secondary btn-sm me-1"
      onclick="document.getElementById('scrape-job-{%d num %}').style.display='block'">
        expand
    </button>
{% endfunc %}

{% func queryArgs(filter *requestFilter, override map[string]string) %}
{% code
	showOnlyUnhealthy := "false"
	if filter.showOnlyUnhealthy {
		showOnlyUnhealthy = "true"
	}
	m := map[string]string{
		"show_only_unhealthy": showOnlyUnhealthy,
		"endpoint_search": filter.endpointSearch,
		"label_search": filter.labelSearch,
	}
	for k, v := range override {
		m[k] = v
	}
	qa := make(url.Values, len(m))
	for k, v := range m {
		qa[k] = []string{v}
	}
%}
	{%s qa.Encode() %}
{% endfunc %}

{% func formatLabels(labels *promutils.Labels) %}
{% code labelsList := labels.GetLabels() %}
{
  {% for i, label := range labelsList %}
      {%s label.Name %}={%q label.Value %}
      {% if i+1 < len(labelsList) %},{% space %}{% endif %}
  {% endfor %}
}
{% endfunc %}

{% endstripspace %}