<?php

namespace common\modules\product\models;

use common\behaviors\SaveMultipleImgBehavior;
use common\behaviors\Slug;
use common\models\ProductToRating;
use common\models\Share;
use common\modules\comment\models\CommentModel;
use common\modules\product\behaviors\FilterBehavior;
use common\modules\rubrication\models\TaxGroup;
use common\modules\rubrication\models\TaxOption;
use Yii;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;
use common\models\Event;
/**
 * This is the model class for table "{{%product}}".
 *
 * @property string $name
 * @property integer $brand_id
 * @property integer $product_id
 * @property Category $category
 * @property array $categories
 * @property array of ProductVariant $variants
 * @property ProductVariant $variant
 * @property ProductImage $image
 * @property array $images
 * @property boolean $is_top
 * @property boolean $is_new
 * @property boolean $akciya
 * @property ProductToRating $averageRating
 * @property array $properties
 * @property ProductVariant $enabledVariant
 * @property array $enabledVariants
 */
class Product extends \yii\db\ActiveRecord
{
    public $_variants = [];
    public $_categories = [];
    public $_options = [];

    /** @var array $_images */
    public $imagesUpload = '';




    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            [
                'class'     => SaveMultipleImgBehavior::className(),
                'fields' => [
                    ['name'=>'imagesUpload','directory' => 'products' ]
                ]
            ],
            [
                'class' => FilterBehavior::className(),
            ],
            [
                'class' => Slug::className(),
                'in_attribute' => 'name',
                'out_attribute' => 'alias',
                'translit' => true
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%product}}';
    }


    /**
     * @return  \yii\db\ActiveQuery
     */
    public function getEvents(){
        return $this->hasMany(Event::className(), ['event_id' => 'event_id'])->viaTable('events_to_products', ['product_id' => 'product_id']);
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
//            [['categories'], 'required'],
            [['brand_id'], 'integer'],
            [['name'], 'string', 'max' => 150],
            [['alias'], 'string', 'max' => 250],
            [['categories', 'variants', 'options', 'imagesUpload'], 'safe'],
//            [['imagesUpload'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, gif', 'maxFiles' => 50],
            [['description', 'video'], 'safe'],
            [['is_top', 'is_new', 'akciya'], 'boolean'],
//            [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'product_id' => Yii::t('product', 'ID'),
            'name' => Yii::t('product', 'Name'),
            'brand_id' => Yii::t('product', 'Brand'),
            'categories' => Yii::t('product', 'Categories'), // relation behavior field
            'category' => Yii::t('product', 'Category'), // relation behavior field
            'image' => Yii::t('product', 'Image'),
            'images' => Yii::t('product', 'Images'),
            'description' => Yii::t('product', 'Description'),
            'video' => Yii::t('product', 'Video embeded'),
            'variants' => Yii::t('product', 'Variants'),
            'is_top' => Yii::t('product', 'Is top'),
            'is_new' => Yii::t('product', 'Is new'),
            'akciya' => Yii::t('product', 'Is promo'),
        ];
    }

    public function getUrl() {
        return '/product/'. $this->alias;
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getBrand()
    {
        return $this->hasOne(Brand::className(), ['brand_id' => 'brand_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getImage()
    {
        return $this->hasOne(ProductImage::className(), ['product_id' => 'product_id']);
    }

    /**
     * fetch stored image url
     * @return string
     */
    public function getImageUrl()
    {

        $image = !empty($this->image) ? $this->image : $this->variant->image;
        return !empty($image) ? $image->imageUrl : '/storage/no_photo.png';
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getImages()
    {
        return $this->hasMany(ProductImage::className(), ['product_id' => 'product_id'])->where(['product_variant_id' => null]);
    }


    /**
     * @return \yii\db\ActiveQuery
     */
    public function getVariant()
    {
        return $this->hasOne(ProductVariant::className(), ['product_id' => 'product_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getVariants()
    {
        return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id']);
    }
    
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getEnabledVariant()
    {
        return $this->hasOne(ProductVariant::className(), ['product_id' => 'product_id'])
            ->andOnCondition(['!=', ProductVariant::tableName() .'.status', 1]);
    }

    public function getVariantPrice() {
        return $this->variant->price;
    }


    public function getPrice() {
        return $this->variant->price;
    }

    public function getEnabledVariantPrice() {
        return $this->enabledVariants[0]->price;
    }



    public function getEnabledVariants()
    {
        return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id'])->andOnCondition(['!=', ProductVariant::tableName() .'.status', 1])->joinWith('image');
    }

    /*
     * Get variants grouped by type
     */
    public function getEnabledVariantsGrouped()
    {
        $variants = [];
        foreach ($this->enabledVariants as $variant) {
            $variants[$variant->product_variant_type_id ? $variant->product_variant_type_id : 1][] = $variant;
        }
        if (empty($variants)) {
            return [];
        }
        $ids = array_keys($variants);
        $variants_type = [];
        foreach(ProductVariantType::find()->select(['product_variant_type_id', 'name2'])->where(['product_variant_type_id' => $ids])->all() as $variant_type) {
            $variant_type->_variants = $variants[$variant_type->product_variant_type_id];
            $variants_type[] = $variant_type;
        }
        return $variants_type;
    }

    public function setVariants($variants) {
        $this->_variants = $variants;
    }

    public function getFullName()
    {
        return empty($this->brand) ? $this->name : $this->brand->name .' '. $this->name;
    }

    public function getCategories() {
        return $this->hasMany(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
//        return $this->getRelations('product_categories');
    }
    public function getCategoriesWithName() {
        return $this->hasMany(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
//        return $this->getRelations('product_categories');
    }

    public function getCategoriesNames() {
        $result = [];
        foreach($this->categories as $category) {
            $result[] = $category->name;
        }
        return $result;
    }

    public function getVariantsWithFilters(){
        return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id'])->with(['filters','image']);
    }
    
    /**
     * @return ActiveQuery
     */
    public function getCategory() {
        return $this->hasOne(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
    }

    public function getOptions() {
        return $this->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])->viaTable('product_option', ['product_id' => 'product_id']);
    }

    public function getProperties() {
        $groups = $options = [];
        foreach ($this->options as $option) {
            $options[$option->tax_group_id][] = $option;
        }
        foreach (TaxGroup::find()->where(['tax_group_id' => array_keys($options)])->all() as $group) {
            if (!empty($options[$group->tax_group_id])) {
                $group->_options = $options[$group->tax_group_id];
                $groups[] = $group;
            }
        }
        return $groups;
    }
    
    public function getActiveProperties($category_id) {
        $cacheKey = ['ActiveProperties','id' => $category_id, 'options' =>$this->options, 'product_id' => $this->product_id ];

        if(!$groups = Yii::$app->cache->get($cacheKey)){

            $groups = $options = [];
            foreach ($this->options as $option) {
                $options[$option->tax_group_id][] = $option;
            }

            $taxGroups = TaxGroup::find()->joinWith('categories')->where(['tax_group.tax_group_id' => array_keys($options), 'tax_group.display' => TRUE, 'category.category_id' => $category_id])->all();

            foreach ($taxGroups as $group) {
                if (!empty($options[$group->tax_group_id])) {
                    $group->_options = $options[$group->tax_group_id];
                    $groups[] = $group;
                }
            }
            Yii::$app->cache->set($cacheKey,$groups,3600*24);
        }

        return $groups;
    }

    public function getStocks() {
        return $this->hasMany(Stock::className(), ['stock_id' => 'stock_id'])->viaTable(ProductStock::tableName(), ['product_id' => 'product_id']);
    }


    public function getQuantity() {
        return ProductStock::find()
            ->where(['product_id' => $this->product_id])
            ->sum('quantity');
    }


    public function beforeSave($insert)
    {

        if(parent::beforeSave($insert)){

            return true;
        }
        return false;



    }

    public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);


        if(!empty($this->categories)){
            $categories = Category::findAll($this->categories);
            $this->unlinkAll('categories', true);
            foreach($categories as $category){
                $this->link('categories', $category);
            }
        }

        if(!empty($this->options)){
            $options = TaxOption::findAll($this->options);
            $this->unlinkAll('options',true);
            foreach($options as $option){
                $this->link('options', $option);
            }
        }


        if (!empty($this->_variants)) {
            $todel = [];
            foreach ($this->variants ?: [] as $_variant) {
                $todel[$_variant->product_variant_id] = $_variant->product_variant_id;
            }
            foreach ($this->_variants as $_variant) {
                if (!is_array($_variant)) {
                    return;
                }
                if (!empty($_variant['product_variant_id'])) {
                    unset($todel[$_variant['product_variant_id']]);
                    $model = ProductVariant::findOne($_variant['product_variant_id']);
                } else {
                    $model = new ProductVariant();
                }
                $_variant['product_id'] = $this->product_id;
                $model->load(['ProductVariant' => $_variant]);
                $model->product_id = $this->product_id;
                $model->save();
            }
            if (!empty($todel)) {
                ProductVariant::deleteAll(['product_variant_id' => $todel]);
            }
        }
    }

    public function beforeDelete() {
        if(parent::beforeDelete()){
            $this->unlinkAll('categories', true);
            $this->unlinkAll('options', true);
            ProductImage::deleteAll(['product_id' => $this->product_id]);

            ProductVariant::deleteAll(['product_id' => $this->product_id]);
            ProductStock::deleteAll(['product_id' => $this->product_id]);
            Share::deleteAll(['product_id' => $this->product_id]);
            return true;
        }
        return false;

    }

    public function imagesUpload()
    {
        if ($this->validate()) {
            $images = [];
            foreach ($this->imagesUpload as $image) {
                $imageName = $image->baseName .'.'. $image->extension;
                $i = 0;
                while(file_exists(Yii::getAlias('@imagesDir/products/' . $imageName))) {
                    $i++;
                    $imageName = $image->baseName .'_'. $i .'.'. $image->extension;
                }
                $imgDir =Yii::getAlias('@imagesDir/products/');
                if(!is_dir($imgDir)) {
                    mkdir($imgDir, 0755, true);
                }


                $image->saveAs($imgDir .$imageName);
                $images[] = $imageName;
            }
            return $images;
        } else {
            return false;
        }
    }

    public function getImagesHTML() {
        $op = [];
        if ($this->images) {
            foreach ($this->images as $image) {
                $op[] = \common\components\artboximage\ArtboxImageHelper::getImage($image->imageUrl, 'admin_thumb');
            }
        }
        return $op;
    }

    public function getImagesConfig() {
        $op = [];
        if ($this->images) {
            foreach ($this->images as $image) {
                $op[] = [
                    'caption' => $image->image,
                    'url' => \yii\helpers\Url::to(['/product/manage/delimg', 'id' => $image->product_image_id]),
                    'key' => $image->product_image_id,
                    'extra' => [
                        'id' => $image->product_image_id,
                    ],
                ];
            }
        }
        return $op;
    }
    
    public function recalculateRating() {
        /**
         * @var ProductToRating $averageRating
         */
        $average = $this->getComments()->joinWith('rating')->select(['average' => 'avg(artbox_comment_rating.value)::float'])->scalar();
        if(!$average) {
            $average = 0;
        }
        $averageRating = $this->averageRating;
        if(!empty($averageRating)) {
            $averageRating->value = $average;
        } else {
            $averageRating = new ProductToRating(['product_id' => $this->product_id, 'value' => $average]);
        }
        if($averageRating->save()) {
            return true;
        } else {
            return false;
        }
    }
    
    public function getComments() {
        return $this->hasMany(CommentModel::className(), ['entity_id' => 'product_id'])->where(['artbox_comment.entity' => self::className(), 'artbox_comment.status' => CommentModel::STATUS_ACTIVE, 'artbox_comment.artbox_comment_pid' => NULL]);
    }

    public function getAverageRating() {
        return $this->hasOne(ProductToRating::className(), ['product_id' => 'product_id']);
    }
    
    public function getTaxGroupsByLevel($level)
    {
        $categories = ArrayHelper::getColumn($this->categories, 'category_id');
        return TaxGroup::find()->distinct()->innerJoin('tax_group_to_category', 'tax_group_to_category.tax_group_id = tax_group.tax_group_id')->andWhere(['tax_group_to_category.category_id' => $categories])->andWhere(['level' => $level]);
    }

    public function setCategories($values)
    {
        $this->categories = $values;
    }

    public function setOptions($values)
    {
        $this->options = $values;
    }

    public function getFilters(){

        return $this->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])
            ->viaTable('product_option',[ 'product_id'=> 'product_id'])
            ->joinWith('taxGroup');
    }

}
