<?php
require_once APPPATH . 'libraries/Cf_REST_Controller.php';

/**
 * @rbacName Modify all users' rules
 * @rbacDescription View, Update, Delete
 * @rbacGroup Widgets
 * @rbacAlias widgets.rules_admin
 */


class Rulesapi extends Cf_REST_Controller
{

    public $username = "";

    function __construct()
    {
        parent::__construct();

        $this->load->model('rules_model');
        $this->load->model('host_model');
        $this->username = $this->session->userdata('username');
    }


    //$rulesIds - can be urlencoded comma separated list
    function rules_get($rulesIds = '')
    {

        $filter = array();
        $filterIds = array();
        //$filter['username'] = $this->session->userdata('username');

        if (!empty($rulesIds))
        {
            $rulesIds = explode(',', urldecode($rulesIds));

            foreach($rulesIds as $item => $id)
            {
                $rulesIds[$item] =  $id;
            }

            $filterIds = array_values($rulesIds);
        }

        try
        {
            $result = $this->rules_model->get_rules_with_ids($filterIds, $filter, array('name' => 'asc'));

            if (empty($result)) {
                $message = $this->lang->line('dashboard_rule_not_exist');
                log_message('debug', 'Failed retrieving rule, error: ' . $message);
                respond_internal_error($message);
                return;
            }

            $json = json_encode($result);
            respond_ok($json);
        }
        catch(Exception $e)
        {
            $message = $e->getMessage();
            log_message('debug', 'Failed retrieving rules, error: ' . $message);
            respond_internal_error($message);
        }
    }

    public function rules_by_export_ids_post()
    {
        $postData = json_decode($this->request->body, true);
        $exportIds = $postData['exportIds'] ?? [];
        $rules = $this->rules_model->get_rules_with_export_ids($exportIds, $this->username);
        if (sizeof($rules) > 0) {
            respond_ok(json_encode($rules));
        } else {
            respond_not_found();
        }
    }

    /**
     * Save rule
     * Allow overwrite only by id
     * same name not allowed  - show error
     *
     *
     * @param <string> $id  - id of the rule. If not provided - assume insert, if provided - assume update
     * @return
     */
    function saverule_post($id = '')
    {

        $data = json_decode($this->request->body, true);

        $data['username'] = $this->session->userdata('username');
        $is_admin = isActionAllowed('widgets.rules_admin');

        if (isset($data['hostcontexts']) && is_array($data['hostcontexts'])) {
            $data['hostcontexts'] = json_encode($data['hostcontexts']);
        }

        $overwrite = FALSE;
        if (!empty($id))
        {
            $overwrite = TRUE;
        }

        try
        {
            $obj = $this->rules_model->saverule($data, $overwrite, $is_admin);
        }
        catch(Exception $e)
        {
            respond_internal_error($e->getMessage());
            return;
        }

        if (!$obj) //not able to get inserted rule
        {
            $errors = $this->rules_model->getErrors();
            $data = json_encode($errors);
            respond_internal_error($data);
            return;
        }
        else
        {
            $data = array();
            $data[0] = array('ruleid' => $obj->id, 'text' => $this->lang->line('dashboard_rule_save_success'), 'errorCode' => 200);
            respond_ok(json_encode($data));
            return;
        }
    }

    function validateCustomSql_post(){
        $data = json_decode($this->request->body, true);
        $obj = $this->rules_model->setRestClient($this->getRestClient());
        $obj = $this->rules_model->validateCustomSql($data['sql']);
        respond_ok(json_encode($obj));
    }

    function deleterule_delete($id) {

        $username = $this->session->userdata('username');
        $is_admin = isActionAllowed('widgets.rules_admin');

        try
        {
            $result = $this->rules_model->deleterule($id, $username, $is_admin);
            $json = json_encode($result);
            respond_ok($json);
        }
        catch(Exception $e)
        {
            $message = $e->getMessage();
            log_message('debug', 'Unable to delete rule. Error: ' . $message);
            respond_internal_error($message);
        }
    }

    public function statistics_post($id)
    {
        $username = $this->session->userdata('username');
        $data = json_decode($this->request->body, true);

        $includes = isset($data['includes']) ? $data['includes'] : [];
        $excludes = isset($data['excludes']) ? $data['excludes'] : [];

        [$rule] = $this->rules_model->get_rules_with_ids([$id], [], array('severity' => 'asc'));

        if (isset($rule->hostcontexts['includes'])) {
            $includes = array_merge($includes, $rule->hostcontexts['includes']);
        }
        $failed = $this->rules_model->getRuleFailHosts($rule, $username, $includes, $excludes);

        $total = null;
        if (sizeof($includes) > 0 || sizeof($excludes) > 0) {
            $total = (int) $this->host_model->getHostCountByContext($username, $includes, $excludes);
        }

        $json = json_encode(['failHosts' => $failed, 'total' => $total]);
        respond_ok($json);
    }
    
    
    public function batch_statistics_post()
    {
        $this->load->driver('cache', array('adapter' => 'file'));
        $username = $this->session->userdata('username');
        $data = json_decode($this->request->body, true);
        $cacheTTL = $this->config->item('compliance_cache_ttl_in_seconds');
        $ids = $data['ids'] ?? [];
        $includes = $data['includes'] ?? [];
        $excludes = $data['excludes'] ?? [];
        $total = (int) $this->host_model->getHostCountByContext($username, $includes, $excludes, fetchDataViaAPI: false);
        $rules = $this->rules_model->get_rules_with_ids($ids);
        $results = [];
 
        foreach ($rules as $rule) {
            $checksFailuresKey = $this->username . '_' . $rule->id . '_checks_failures';
            $mergedIncludes = isset($rule->hostcontexts['includes']) ? array_merge($includes, $rule->hostcontexts['includes']) : $includes;
            
            if ($this->cache->get($checksFailuresKey) !== false) {
                $failed = $this->cache->get($checksFailuresKey);
            } else {
                $failed = $this->rules_model->getRuleFailHosts($rule, $username, $mergedIncludes, $excludes, fetchDataViaAPI: false);
                $this->cache->save($checksFailuresKey, $failed, $cacheTTL);
            }
            
            // if the rule does not have includes then use common total hosts count
            if (isset($rule->hostcontexts['includes'])) {
                $totalChecksHostsKey = $this->username . '_' . base64_encode(json_encode($mergedIncludes)) . '_checks_failures';
                if ($this->cache->get($totalChecksHostsKey) !== false) {
                    $total = $this->cache->get($totalChecksHostsKey);
                } else {
                    $total = (int)$this->host_model->getHostCountByContext($username, $mergedIncludes, $excludes, fetchDataViaAPI: false);
                    $this->cache->save($totalChecksHostsKey, $total, $cacheTTL);
                }
            }
            
            $results[] = ['ruleId' => $rule->id,'failHosts' => $failed, 'total' => $total];
        }

        respond_ok(json_encode($results));
    }
 }
