<?php

namespace idoit\Module\Nagios\Console\Command;

use Exception;
use idoit\Console\Command\AbstractCommand;
use isys_cmdb_dao_category_g_nagios;
use isys_component_dao_logbook;
use isys_component_dao_ndo;
use isys_factory;
use isys_monitoring_helper;
use isys_monitoring_ndo;
use isys_nagios_helper;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class NagiosCommand extends AbstractCommand
{
    const NAME = 'nagios-ndoutils';

    /**
     * @var OutputInterface
     */
    private $output;

    /**
     * NDO component DAO.
     *
     * @var  isys_component_dao_ndo
     */
    private $m_comp_dao_ndo;

    /**
     * Logbook DAO.
     *
     * @var  isys_component_dao_logbook
     */
    private $m_dao_logbook;

    /**
     * Nagios category DAO.
     *
     * @var  isys_cmdb_dao_category_g_nagios
     */
    private $m_dao_nagios;

    /**
     * Get name for command
     *
     * @return string
     */
    public function getCommandName()
    {
        return self::NAME;
    }

    /**
     * Get description for command
     *
     * @return string
     */
    public function getCommandDescription()
    {
        return 'Imports monitoring status changes from NDOUtils into the i-doit logbook';
    }

    /**
     * Retrieve Command InputDefinition
     *
     * @return InputDefinition
     */
    public function getCommandDefinition()
    {
        $definition = new InputDefinition();

        return $definition;
    }

    /**
     * Checks if a command can have a config file via --config
     *
     * @return bool
     */
    public function isConfigurable()
    {
        return true;
    }

    /**
     * Returns an array of command usages
     *
     * @return string[]
     */
    public function getCommandUsages()
    {
        return [];
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->output = $output;
        $this->output->writeln("Setting up system environment");

        // Get daos, because now we are logged in.
        $this->m_dao_nagios = new isys_cmdb_dao_category_g_nagios($this->container->database);
        $this->m_dao_logbook = new isys_component_dao_logbook($this->container->database);

        $this->output->writeln("Nagios-Handler initialized (" . date("Y-m-d H:i:s") . ")");

        // Check status and add to logbook.
        $this->processStateHistory();
    }

    /**
     * Process state history method.
     *
     * @throws  Exception
     */
    private function processStateHistory()
    {
        $l_monitoring_dao = isys_factory::get_instance('isys_cmdb_dao_category_g_monitoring', $this->container->database);

        $l_hosts_res = $l_monitoring_dao->get_data(null, null,
            'AND isys_monitoring_hosts__active = 1 AND isys_monitoring_hosts__type = ' . $l_monitoring_dao->convert_sql_text(C__MONITORING__TYPE_NDO), null,
            C__RECORD_STATUS__NORMAL);

        $l_hosts_num = count($l_hosts_res);

        // We need to initialize the nagios helper.
        isys_nagios_helper::init();

        $this->output->writeln('Found ' . $l_hosts_num . ($l_hosts_num == 1 ? ' host' : ' hosts'));

        if ($l_hosts_num > 0) {
            while ($l_row = $l_hosts_res->get_row()) {
                $l_objID = $l_row["isys_obj__id"];
                $l_hostname = isys_monitoring_helper::render_export_hostname($l_row['isys_obj__id']);

                $this->output->writeln('Processing "' . $l_hostname . '"');

                try {
                    try {
                        if ($l_row["isys_catg_monitoring_list__isys_monitoring_hosts__id"] > 0) {
                            $this->output->writeln('..', false);
                            $l_ndo_instance = isys_monitoring_ndo::factory($l_row["isys_catg_monitoring_list__isys_monitoring_hosts__id"]);
                        } else {
                            $this->output->writeln(' ..this object has no assigned monitoring host [SKIP]');
                            continue;
                        }
                    } catch (Exception $e) {
                        $this->output->writeln('  ' . $l_hostname . ': ' . $e->getMessage() . ' [SKIP]');
                        continue;
                    }

                    $this->m_comp_dao_ndo = new isys_component_dao_ndo($l_ndo_instance->get_db_connection(), $l_ndo_instance->get_db_prefix());

                    if (!$this->m_comp_dao_ndo->hostExists($l_hostname)) {
                        throw new Exception("  Host does not exist in your NDO database [SKIP]");
                    }

                    $l_hist = $this->m_comp_dao_ndo->getHostStateHistory($l_hostname);
                    $l_date = $this->m_dao_logbook->getDateOfLastNDOEntry($l_objID);

                    foreach ($l_hist as $val) {
                        if ($val["state_time"] <= $l_date) {
                            break;
                        }

                        switch ($val["state"]) {
                            case "0":
                                $this->output->writeln("  is UP");
                                $this->m_dao_logbook->set_entry($l_hostname . ": UP", "State time: " . $val["state_time"] . "<br/>" . $val["output"], $val["state_time"],
                                    C__LOGBOOK__ALERT_LEVEL__1, $l_objID, null, null, null, C__LOGBOOK_SOURCE__NDO);
                                break;

                            case "1":
                                $this->output->writeln("  is DOWN");
                                $this->m_dao_logbook->set_entry($l_hostname . ": DOWN", "State time: " . $val["state_time"] . "<br/>" . $val["output"], $val["state_time"],
                                    C__LOGBOOK__ALERT_LEVEL__3, $l_objID, null, null, null, C__LOGBOOK_SOURCE__NDO);
                                break;

                            case "2":
                                $this->output->writeln("  is UNREACHABLE");
                                $this->m_dao_logbook->set_entry($l_hostname . ": UNREACHABLE", "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                    $val["state_time"], C__LOGBOOK__ALERT_LEVEL__2, $l_objID, null, null, null, C__LOGBOOK_SOURCE__NDO);
                                break;

                            default:
                                throw new Exception("Error");
                        }
                    }

                    $l_service_res = $this->m_dao_nagios->getActiveServices($l_objID);

                    if (count($l_service_res) > 0) {
                        while ($l_service_row = $l_service_res->get_row()) {
                            if (!$this->m_comp_dao_ndo->serviceExists($l_hostname, $l_service_row["service_description"])) {
                                continue;
                            }

                            $l_hist = $this->m_comp_dao_ndo->getServiceStateHistory($l_hostname, $l_service_row["service_description"]);
                            $l_date = $this->m_dao_logbook->getDateOfLastNDOEntry($l_service_row["service_obj_id"]);

                            foreach ($l_hist as $val) {
                                if ($val["state_time"] <= $l_date) {
                                    break;
                                }

                                switch ($val["state"]) {
                                    case "0":
                                        $this->m_dao_logbook->set_entry($l_service_row["service_description"] . "(" . $l_hostname . "): OK",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"], $val["state_time"], C__LOGBOOK__ALERT_LEVEL__1,
                                            $l_service_row["service_obj_id"], null, null, null, C__LOGBOOK_SOURCE__NDO);
                                        break;

                                    case "1":
                                        $this->m_dao_logbook->set_entry($l_service_row["service_description"] . "(" . $l_hostname . "): WARNING",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"], $val["state_time"], C__LOGBOOK__ALERT_LEVEL__2,
                                            $l_service_row["service_obj_id"], null, null, null, C__LOGBOOK_SOURCE__NDO);

                                        break;

                                    case "2":
                                        $this->m_dao_logbook->set_entry($l_service_row["service_description"] . "(" . $l_hostname . "): CRITICAL",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"], $val["state_time"], C__LOGBOOK__ALERT_LEVEL__3,
                                            $l_service_row["service_obj_id"], null, null, null, C__LOGBOOK_SOURCE__NDO);

                                        break;

                                    case "3":
                                        $this->m_dao_logbook->set_entry($l_service_row["service_description"] . "(" . $l_hostname . "): UNKNOWN",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"], $val["state_time"], C__LOGBOOK__ALERT_LEVEL__2,
                                            $l_service_row["service_obj_id"], null, null, null, C__LOGBOOK_SOURCE__NDO);

                                        break;

                                    default:
                                        $this->output->writeln("Processing of " . $val["isys_catg_application_list__service_description"] . " on " . $l_hostname . " failed");
                                }
                            }
                        }
                    }
                } catch (Exception $e) {
                    $this->output->writeln('  ' . $l_hostname . ': ' . $e->getMessage());
                }
            }
        }
    }
}
