<?php

namespace Velis\Bpm;

use InvalidArgumentException;
use ReflectionException;
use Velis\Bpm\Product\Category;
use Velis\Filter;
use Velis\Lang;
use Velis\Model\Cacheable;
use Velis\Model\DataObject;
use Velis\Model\Routable;
use Velis\Output;

/**
 * Vendor model
 *
 * @author Olek Procki <olo@velis.pl>
 * @author Bartosz Izdebski <bartosz.izdebski@velis.pl>
 */
class Vendor extends DataObject implements Cacheable, Routable
{
    /**
     * Assigned product categories
     * @var Category[]
     */
    protected $_productCategories;


    /**
     * List sort options
     */
    protected static $_listDefaultOrder = 'name ASC';


    /**
     * @return string
     */
    protected function _getTableName()
    {
        return 'app.vendor_tab';
    }


    /**
     * Returns rewrite route name
     * @return string
     */
    public function getRouteName()
    {
        return 'vendor';
    }


    /**
     * Returns standard non-rewrite url
     * @return string
     */
    public function getStandardUrl()
    {
        return '/product/vendor/?vendor_id=' . $this->id();
    }


    /**
     * Returns vendor name
     * @return string
     */
    public function getName()
    {
        return $this['name'];
    }


    /**
     * Validate PK format
     * @return void
     * @throws InvalidArgumentException
     */
    protected function validate()
    {
        if (!preg_match('/^[a-z0-9]+$/i', $this->id())) {
            throw new InvalidArgumentException(
                sprintf('%s: %s - %s', Lang::get('GENERAL_INVALID_ACRONYM_FORMAT'), Filter::filterXss($this->id()), mb_strtolower(Lang::get('GENERAL_ALPHANUMERIC_CHARS_ONLY')))
            );
        }
    }


    /**
     * Prepares object before saving
     * @return $this
     */
    public function prepare()
    {
        $this->validate();

        $this['vendor_id'] = Output::acronym(
            $this->id(),
            Output::ACRO_UNDERSCORE
        );

        return $this;
    }


    /**
     * {@inheritDoc}
     */
    public function modify($checkDiff = false)
    {
        $this->prepare();

        return parent::modify($checkDiff);
    }


    /**
     * {@inheritDoc}
     */
    public function add($updateObjectId = false)
    {
        $this->prepare();

        return parent::add($updateObjectId);
    }


    /**
     * Removes vendor
     * @return bool
     */
    public function remove()
    {
        return parent::_remove();
    }


    /**
     * Returns assigned product categories
     * @return Category[]
     * @throws ReflectionException
     */
    public function getProductCategories()
    {
        if (!isset($this->_productCategories)) {
            $this->_productCategories = Category::listAll($this->_getPrimaryKeyParam());
        }

        return $this->_productCategories;
    }


    /**
     * Adds product category
     *
     * @param Category|int $category
     * @return $this
     */
    public function addProductCategory($category)
    {
        $categoryId = $category instanceof Category ? $category->id() : $category;

        self::$_db->insert(
            'app.vendor_product_category_tab',
            array(
                'vendor_id' => $this->id(),
                'product_category_id' => $categoryId
            )
        );

        unset($this->_productCategories);

        return $this;
    }


    /**
     * Removes product category assignment
     *
     * @param Category|int $category
     * @return $this
     */
    public function removeProductCategory($category)
    {
        $categoryId = $category instanceof Category ? $category->id() : $category;

        self::$_db->execDML(
            'DELETE FROM app.vendor_product_category_tab
                WHERE vendor_id=:vendor_id
                  AND product_category_id=:product_category_id',
            [
                'vendor_id' => $this->id(),
                'product_category_id' => $categoryId,
            ]
        );

        unset($this->_productCategories[$categoryId]);

        return $this;
    }


    /**
     * Returns true if vendor has product category assigned
     *
     * @param Category|int $category
     * @return bool
     * @throws ReflectionException
     */
    public function hasCategory($category)
    {
        $categoryId = $category instanceof Category ? $category->id() : $category;

        return array_key_exists($categoryId, $this->getProductCategories());
    }


    /**
     * Returns active vendors list
     * @return Vendor[]
     */
    public static function listActive()
    {
        $activeVendors = array();
        foreach (self::listCached() as $vendor) {
            if ($vendor['active']) {
                $activeVendors[$vendor->id()] = $vendor;
            }
        }
        return $activeVendors;
    }
}
