<?php

/*
 * @component UserPoints
 * @copyright Copyright (C) 2015-2022 Bernard Gilly - Adrien Roussel - Martin Brampton
 * @license : GNU/GPL
 * @Website : https://remository.com
 */

namespace BlackSheepResearch\Component\UserPoints\Site\Problems;

defined('_JEXEC') or die;

use BlackSheepResearch\Component\UserPoints\Site\UserPoints;

class Rule extends ProblemBase {

    protected static $fieldnames = [];
    protected static $fieldtypes = [];
    protected static $count = -1;
    protected static $tablename = '#__alpha_userpoints_rules';
    protected static $updatetable = '#__alpha_userpoints_rules';
    protected static $keyname = 'id';
    private static $rules = [];
    private static $rules_by_name = [];

    public function __construct() {
        parent::__construct();
    }
    
    protected function initialise () {
        $this->loadRules();
        self::$count = count(self::$rules);
    }

    public static function withRuleName (string $rule_name) {
        $rule = new self();
        if (isset(self::$rules_by_name[$rule_name])) {
            $id = self::$rules_by_name[$rule_name];
            $rule->problem_object = self::$rules[$id];
        }
        return $rule;
    }
    
    public static function withRuleID (int $id) {
        $rule = new self();
        if (isset(self::$rules[$id])) {
            $rule->problem_object = self::$rules[$id];
        }
        return $rule;
    }

    private function loadRules() {
        foreach ($this->getAllRecords() as $result) {
            self::$rules[$result->id] = $result;
            self::$rules_by_name[$result->plugin_function] = $result->id;
        }
    }

    private function setObject($object) {
        $this->problem_object = $object;
        return $this;
    }
    
    public static function allPublished () : array {
        $results = [];
        foreach (self::$rules as $rule) {
            if ($rule->published) {
                $results[] = $rule;
            }
        }
        return $results;
    }

    public function checkEnabled() {
        $now = self::datetimeSQL();
        return ($this->problem_object AND $this->published AND ($this->rule_expire > $now OR $this->rule_expire = SQL::nulldatetimeSQL()));
    }

    public function checkForAccess($authorizedLevels, $force = 0) {
        if ($this->checkEnabled()) {
            if ($force OR 0 == $this->access) {
                return true;
            }
            $allowAllLevels = [
                'sysplgup_referralpoints',
                'sysplgup_emailnotification',
                'sysplgup_winnernotification',
                'sysplgup_newregistered',
                'sysplgup_invitewithsuccess',
                'sysplgup_archive',
                'sysplgup_changelevel1',
                'sysplgup_changelevel2',
                'sysplgup_changelevel3'
            ];
            if (in_array($this->plugin_function, $allowAllLevels) OR in_array($this->access, $authorizedLevels)) {
                return true;
            }
        }
        return false;
    }

    public static function getAll() {
        return self::makeProblems(self::$rules);
    }

    public static function reset() {
        self::$rules = [];
        self::$rules_by_name = [];
    }

    public static function getIDFromRuleName($rule_name) {
        new self();
        return isset(self::$rules_by_name[$rule_name]) ? self::$rules_by_name[$rule_name] : 0;
    }

    public static function getIDFromRuleNamePublished($rule_name) {
        $id = self::getIDFromRuleName($rule_name);
        if (isset(self::$rules[$id]) AND self::$rules[$id]->published != 0) {
            return $id;
        }
        return 0;
    }

    public static function getActiveByRuleName($rule_name) {
        $rule = self::withRuleName($rule_name);
        if ($rule AND $rule->published != 0 AND ($rule->rule_expire > self::datetimeSQL() OR $rule->rule_expire = SQL::nulldatetimeSQL())) {
            return $rule;
        }
        return null;
    }

    public static function getChainedRules($current_id) {
        foreach (self::getAll() as $id => $rule) {
            if ($id == $current_id OR 0 == $rule->published OR 0 == $rule->chain) {
                continue;
            }
            $rules[] = $rule;
        }
        return isset($rules) ? $rules : [];
    }

    public static function getRulesWithViewlevels($filter, int $limitstart, int $limit, &$total) {
        $db = SQL::getInstance();
        $query = "SELECT %s FROM %s AS r LEFT JOIN #__viewlevels AS v ON v.id=r.access %s %s %s";
        $countq = sprintf($query, 'COUNT(*)', self::$tablename, $filter, '', '');
        $db->setQuery($countq);
        $total = $db->loadResult();
        $fetchq = sprintf($query, 'r.*, v.title AS groupname', self::$tablename, $filter, 'ORDER BY r.category', "LIMIT $limitstart, $limit");
        $db->setQuery($fetchq);
        $objects = (array) $db->loadObjectList();
        foreach ($objects as $object) {
            $rules[] = (new self())->setObject($object);
        }
        return isset($rules) ? $rules : null;
    }

    public static function removeFromChangeLevelsGroups(int $userid) {
        $table = self::$tablename;
        $db = SQL::getInstance();
        $db->setQuery("DELETE m FROM #__user_usergroup_map AS m "
                . " INNER JOIN `$table` AS r "
                . " ON r.plugin_function LIKE 'sysplgup_changelevel%'  AND CAST(r.content_items AS UNSIGNED) = m.group_id "
                . " WHERE r.content_items REGEXP '^[0-9]+$'  AND m.user_id = $userid");
        $db->execute();
    }

    public static function getRulesList() {
        // Get the pagination request variables
        list($limitstart, $limit) = self::getLimitsFromRequest();

        // hide defined rules from list
        //$hiderule = array();
        $params = UserPoints::getMenuParameters();
        $hide_rules = $params->get('hide_rule_byid',0);
        if ($hide_rules) {
            $where[] = "id NOT IN ($hide_rules)";
        }
        $where[] = $params->get('show_published', 1) ? 'published = 1' : 'pubished=0';
        switch ($params->get('order_by',0)) {
            case 2:
                $show_order = " ORDER BY points DESC, id ASC";
                break;
            case 1:
                $show_order = " ORDER BY category ASC, points DESC";
                break;
            default:
                $show_order = " ORDER BY id ASC";
        }
        $db = SQL::getInstance();
        $table = self::$tablename;
        $q = "SELECT %s FROM `$table` WHERE %s %s";
        $db->setQuery(sprintf($q, 'COUNT(*)', implode(' AND ', $where), ''));
        $total = $db->loadResult();
        $db->setQuery(sprintf($q, '*', implode(' AND ', $where), $show_order));
        $results = (array) $db->loadObjectList();
        return array($results, $total, $limit, $limitstart);
    }
}
