#!/usr/bin/env python3
# Copyright (C) 2019 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

# <<<jenkins_queue>>>
# [[u'[{"task": {"color": "blue_anime", "_class":
# "org.jenkinsci.plugins.workflow.job.WorkflowJob", "name": "testbuild"},
# "inQueueSince": 1566823138742, "why": "Build #471 is already in progress
# (ETA: 38 min)", "stuck": false, "_class": "hudson.model.Queue$BlockedItem",
# "buildableStartMilliseconds": 1566823144626, "id": 174032, "blocked":
# true}]']]


import json
import time

from cmk.base.check_api import check_levels, LegacyCheckDefinition, state_markers
from cmk.base.config import check_info

from cmk.agent_based.v2 import render

MAP_QUEUE_STATES = {
    True: "yes",
    False: "no",
}


def parse_jenkins_queue(string_table):
    parsed = []

    for line in string_table:
        parsed.extend(json.loads(line[0]))

    return parsed


def inventory_jenkins_queue(parsed):
    yield None, {}


def check_jenkins_queue(_no_item, params, parsed):
    if not parsed:
        yield 0, "Queue length: 0 Tasks"
        return

    long_output = []

    yield check_levels(
        len(parsed),
        "queue",
        params.get("queue_length"),
        human_readable_func=int,
        unit="Tasks",
        infoname="Queue length",
    )

    levels = params["in_queue_since"]
    stuck_tasks = 0
    blocked_tasks = 0
    pending_tasks = 0

    for task in sorted(
        parsed, key=lambda k: (k["stuck"], k["blocked"], -k["inQueueSince"]), reverse=True
    ):
        now = time.time()
        len_state = 0
        timestamp_in_queue = task["inQueueSince"] / 1000
        since = now - timestamp_in_queue

        len_state, _since_infotext, _perf_data = check_levels(since, None, levels)

        stuck_state = 0
        if task["stuck"]:
            stuck_tasks += 1
            stuck_state = params["stuck"]

        blocked_state = 0
        if task["blocked"]:
            blocked_tasks += 1
            blocked_state = params["blocked"]

        long_output_str = "ID: %d, Stuck: %s%s, Blocked: %s%s" % (
            task["id"],
            MAP_QUEUE_STATES[task["stuck"]],
            state_markers[stuck_state],
            MAP_QUEUE_STATES[task["blocked"]],
            state_markers[blocked_state],
        )

        pending_state = 0
        # pending can be missing
        task_pending = task.get("pending")
        if task_pending or task_pending is False:
            if task_pending:
                pending_tasks += 1
            pending_state = params["pending"]
            long_output_str += ", Pending: {}{}".format(
                MAP_QUEUE_STATES[task_pending],
                state_markers[pending_state],
            )

        long_output_str += ", In queue since: {} ({})".format(
            render.timespan(since),
            render.datetime(timestamp_in_queue),
        )

        if len_state:
            long_output_str += " (warn/crit at {}/{}){}".format(
                render.timespan(levels[0]),
                render.timespan(levels[1]),
                state_markers[len_state],
            )

        state = max([len_state, stuck_state, blocked_state, pending_state])

        long_output_str += ", Why kept: %s" % task["why"]

        long_output.append((state, long_output_str))

    max_state = max(state for state, _infotext in long_output)

    for key, value, infotext in [
        (stuck_tasks, "stuck_tasks", "Stuck"),
        (blocked_tasks, "blocked_tasks", "Blocked"),
        (pending_tasks, "pending_tasks", "Pending"),
    ]:
        jenkins_value = "jenkins_%s" % value

        yield check_levels(
            key,
            jenkins_value,
            params.get(jenkins_value),
            human_readable_func=int,
            infoname=infotext,
        )

    if long_output:
        yield max_state, "See long output for further information"

        for state, line in long_output:
            yield 0, "\n%s" % line


check_info["jenkins_queue"] = LegacyCheckDefinition(
    parse_function=parse_jenkins_queue,
    service_name="Jenkins Queue",
    discovery_function=inventory_jenkins_queue,
    check_function=check_jenkins_queue,
    check_ruleset_name="jenkins_queue",
    check_default_parameters={
        "in_queue_since": (3600, 7200),
        "stuck": 2,
        "blocked": 0,
        "pending": 0,
        "jenkins_stuck_tasks": (1, 2),
    },
)
