<?php

namespace Velis\Bpm\Ticket;

use Velis\Model\Hierarchical;
use Velis\Model\Cacheable;
use Velis\Model\Sanitizable;
use Velis\App;
use Velis\Lang;
use User\User;

/**
 * Ticket category model
 * @author Olek Procki <olo@velis.pl>
 * @author Robert Jamróz <robert.jamroz@velis.pl>
 */
class Category extends Hierarchical implements Cacheable, Sanitizable
{
    /**
     * Buffer for not cached model type (must be redeclared in Cachable class)
     * @var \Velis\Model\Hierarchical[]
     */
    protected static $_source;

    /**
     * Default list order
     * @var string
     */
    protected static $_listDefaultOrder = 'ticket_type_id, name_pl';


    /**
     * Returns related table name
     * @return string
     */
    protected function _getTableName()
    {
        return 'app.ticket_category_tab';
    }


    /**
     * Returns view as datasource
     * @return string
     */
    protected function _getListDatasource()
    {
        return 'app.ticket_category';
    }


    /**
     * Returns categories list with nested order (depth info included as 'level' field)
     *
     * @param array<string, mixed>|null $filter
     * @param array<static>|null $predefinedList
     * @return array<static>
     */
    public static function getNestedList(array $filter = null, array $predefinedList = null)
    {
        if (null === $filter) {
            $filter = ['active' => 1];
        }

        return parent::getNestedList($filter, $predefinedList);
    }

    /**
     * Returns nested list grouped by ticket type
     * @return array<static>
     */
    public static function getNestedByType(array $filter = array('active' => 1))
    {
        $types = Ticket::getTypes();
        asort($types);

        $list = array();

        foreach ($types as $typeId => $type) {
            $list = $list + self::getNestedList(
                array_merge($filter, array('ticket_type_id' => $typeId))
            );
        }
        return $list;
    }


    /**
     * Returns categories json representation
     *
     * @param array $filter
     * @return string
     */
    public static function getElementsJSON(array $filter = null, bool $nested = false)
    {
        if (null === $filter) {
            $filter = ['active' => 1];
        }

        return parent::getElementsJSON($filter);
    }


    /**
     * Returns category name
     * @return string
     */
    public function getName()
    {
        return $this['name_' . Lang::getLanguage()];
    }


    /**
     * Returns category parent id
     * @return int
     */
    public function getParentId()
    {
        return $this['parent_ticket_category_id'];
    }


    /**
     * Returns true if category can be chosen
     * @return bool
     */
    public function isActive()
    {
        return $this['active'] == 1;
    }


    /**
     * Returns category operators
     *
     * @param array $params
     * @param bool $includeDefault
     *
     * @return \Velis\User[]
     */
    public function getOperators(array $params = array(), $includeDefault = true, bool $onlyActive = false)
    {
        if (empty($params) && isset($this['user_matrix_ids'])) {
            // matrix users cached in view return them immediately as ids
            if ($this['user_matrix_ids'] || !$includeDefault) {
                return explode(',', $this['user_matrix_ids']);
            } else {
                return array(App::$config->settings->defaultOperator);
            }
        }

        $params = array_merge($params, array('ticket_category_id' => $this['ticket_category_id']));
        $ticketSpecs = Factory::getRegisteredSpecs();

        if ($ticketClass = $ticketSpecs[$this['ticket_type_id']]) {
            if ($ticketClass::$matrixClass) {
                $matrixClass = $ticketClass::$matrixClass;
            } else {
                $matrixClass = reset(array_filter(explode('\\', $ticketSpecs[$this['ticket_type_id']]))) . '\CategoryMatrix';
            }
        }

        if (!$matrixClass || !class_exists($matrixClass)) {
            if (class_exists('\Ticket\CategoryMatrix')) {
                $matrixClass = '\Ticket\CategoryMatrix';
            } else {
                $matrixClass = '\Velis\Bpm\Ticket\CategoryMatrix';
            }
        }

        $matrix = $matrixClass::listAll($params);
        $operators = array();

        foreach ($matrix as $elem) {
            $operator = $elem->getOperator();

            if (!$operator->belongs($operators)) {
                if ($onlyActive && $operator instanceof User && !$operator->isActive()) {
                    continue;
                } else {
                    $operators[] = $operator;
                }
            }
        }

        if (empty($operators)) {
            if ($this->isMainElement()) {
                if ($includeDefault && App::$config->settings->defaultOperator) {
                    $operator = User::bufferedInstance(App::$config->settings->defaultOperator);
                    if ($operator) {
                        $operators[] = $operator;
                    }
                }
            } else {
                return $this->getParent()->getOperators($params, $includeDefault);
            }
        }

        return $operators;
    }

    /**
     * {@inheritDoc}
     */
    public static function compareNames(Hierarchical $element1, Hierarchical $element2)
    {
        $name1 = '';
        $name2 = '';

        if (static::hasField('sort_order', true)) {
            $name1 = str_pad($element1->sort_order, 5, "0", STR_PAD_LEFT) . '-' . $element1->getName();
            $name2 = str_pad($element2->sort_order, 5, "0", STR_PAD_LEFT) . '-' . $element2->getName();

            if (is_null($element1->sort_order) && is_null($element2->sort_order)) {
                return strcasecmp($name1, $name2);
            } else if (is_null($element1->sort_order)) {
                return 1;
            } elseif (is_null($element2->sort_order)) {
                return -1;
            }
        } else {
            $name1 = $element1->getName();
            $name2 = $element2->getName();

            if ($name1 == 'Inne') {
                return 1;
            } elseif ($name2 == 'Inne') {
                return -1;
            }
        }

        return strcasecmp($name1, $name2);
    }
}
