<?php
    
    namespace common\modules\product\models;
    
    use common\behaviors\MultipleImgBehavior;
    use common\behaviors\SaveMultipleFileBehavior;
    use common\behaviors\TechBehavior;
    use common\models\ProductCertificate;
    use common\models\ProductSpec;
    use common\models\ProductToRating;
    use common\modules\comment\models\CommentModel;
    use common\modules\language\behaviors\LanguageBehavior;
    use common\modules\product\behaviors\DefaultVariantBehavior;
    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 yii\web\Request;
    
    /**
     * This is the model class for table "{{%product}}".
     * @property integer              $brand_id
     * @property integer              $product_id
     * @property Category             $category
     * @property Category[]           $categories
     * @property ProductVariant[]     $variants
     * @property ProductVariant       $variant
     * @property boolean              $is_top
     * @property boolean              $is_new
     * @property boolean              $akciya
     * @property ProductToRating      $averageRating
     * @property array                $properties
     * @property ProductVariant       $enabledVariant
     * @property ProductVariant[]     $enabledVariants
     * @property string               $video
     * @property TaxOption[]          $options
     * @property Brand                $brand
     * @property ProductSpec          $productSpec
     * @property ProductCertificate[] $productCertificates
     * * From language behavior *
     * @property ProductLang          $lang
     * @property ProductLang[]        $langs
     * @property ProductLang          $object_lang
     * @property string               $ownerKey
     * @property string               $langKey
     * @property ProductLang[]        $model_langs
     * @property bool                 $transactionStatus
     * @method string           getOwnerKey()
     * @method void             setOwnerKey( string $value )
     * @method string           getLangKey()
     * @method void             setLangKey( string $value )
     * @method ActiveQuery      getLangs()
     * @method ActiveQuery      getLang( integer $language_id )
     * @method ProductLang[]    generateLangs()
     * @method void             loadLangs( Request $request )
     * @method bool             linkLangs()
     * @method bool             saveLangs()
     * @method bool             getTransactionStatus()
     * * End language behavior *
     * * From multipleImage behavior
     * @property ProductImage         $image
     * @property ProductImage[]       $images
     * @method ActiveQuery getImage()
     * @method ActiveQuery getImages()
     * @method array getImagesConfig()
     * @method array getImagesHTML( string $preset )
     * * End multipleImage behavior
     */
    class Product extends \yii\db\ActiveRecord
    {
        
        /** @var array $_variants */
        public $_variants = [];
        
        public $imagesUpload = [];
        
        public $certificateUpload = [];
        
        /**
         * @inheritdoc
         */
        public function behaviors()
        {
            return [
                'images'        => [
                    'class'     => SaveMultipleFileBehavior::className(),
                    'name'      => 'imagesUpload',
                    'directory' => 'products',
                    'column'    => 'image',
                    'links'     => [
                        'product_id' => 'product_id',
                    ],
                    'model'     => ProductImage::className(),
                ],
                'certificates'  => [
                    'class'     => SaveMultipleFileBehavior::className(),
                    'name'      => 'certificateUpload',
                    'directory' => 'certificates',
                    'column'    => 'link',
                    'links'     => [
                        'product_id' => 'product_id',
                    ],
                    'model'     => ProductCertificate::className(),
                ],
                'multipleImage' => [
                    'class'  => MultipleImgBehavior::className(),
                    'links'  => [
                        'product_id' => 'product_id',
                    ],
                    'conditions' => [
                        'product_variant_id' => NULL,
                    ],
                    'model'  => ProductImage::className(),
                    'config' => [
                        'caption'       => 'image',
                        'delete_action' => '/product/manage/delimg',
                        'id'            => 'product_image_id',
                    ],
                ],
                [
                    'class' => FilterBehavior::className(),
                ],
                'language'      => [
                    'class' => LanguageBehavior::className(),
                ],
                'techSpec' => [
                    'class' => TechBehavior::className(),
                ],
//                'defaultVariant' => [
//                    'class' => DefaultVariantBehavior::className(),
//                ],
            ];
        }
        
        /**
         * @inheritdoc
         */
        public static function tableName()
        {
            return 'product';
        }
        
        /**
         * @inheritdoc
         */
        public function rules()
        {
            return [
                [
                    [ 'brand_id' ],
                    'integer',
                ],
                [
                    [
                        'categories',
                        'variants',
                        'options',
                        'imagesUpload',
                        'certificateUpload',
                    ],
                    'safe',
                ],
                [
                    [
                        'video',
                    ],
                    'safe',
                ],
                [
                    [
                        'is_top',
                        'is_new',
                        'akciya',
                    ],
                    'boolean',
                ],
            ];
        }
        
        /**
         * @inheritdoc
         */
        public function attributeLabels()
        {
            return [
                'product_id' => Yii::t('product', 'ID'),
                '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'),
                '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'),
            ];
        }
        
        /**
         * @return \yii\db\ActiveQuery
         */
        public function getBrand()
        {
            return $this->hasOne(Brand::className(), [ 'brand_id' => 'brand_id' ]);
        }
        
        /**
         * @return \yii\db\ActiveQuery
         */
        public function getVariant()
        {
            return $this->hasOne(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() . '.stock',
                            0,
                        ]);
        }
        
        public function getVariantPrice()
        {
            return $this->variant->price;
        }
        
        public function getEnabledVariantPrice()
        {
            return $this->enabledVariants[ 0 ]->price;
        }
        
        /**
         * @return \yii\db\ActiveQuery
         */
        public function getVariants()
        {
            return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'product_id' ]);
        }
        
        public function getEnabledVariants()
        {
            return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'product_id' ])
                        ->andOnCondition([
                            '!=',
                            ProductVariant::tableName() . '.stock',
                            0,
                        ])
                        ->joinWith('image');
        }
        
        public function setVariants($variants)
        {
            $this->_variants = $variants;
        }
        
        public function getFullName()
        {
            return empty( $this->brand ) ? $this->lang->name : $this->brand->lang->name . ' ' . $this->lang->name;
        }
        
        /**
         * @return ActiveQuery
         */
        public function getCategories()
        {
            return $this->hasMany(Category::className(), [ 'category_id' => 'category_id' ])
                        ->viaTable('product_category', [ 'product_id' => 'product_id' ]);
        }
        
        public function getCategoriesNames()
        {
            $result = [];
            foreach($this->categories as $category) {
                $result[] = $category->lang->name;
            }
            return $result;
        }
        
        public function getVariantsWithFilters()
        {
            return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'product_id' ])
                        ->joinWith('lang', true, 'INNER JOIN')
                        ->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' ]);
        }
        
        /**
         * @return TaxGroup[]
         */
        public function getProperties()
        {
            $groups = $options = [];
            foreach($this->getOptions()
                         ->with('lang')
                         ->all() as $option) {
                $options[ $option->tax_group_id ][] = $option;
            }
            foreach(TaxGroup::find()
                            ->where([ 'tax_group_id' => array_keys($options) ])
                            ->with('lang')
                            ->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)
        {
            $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;
                }
            }
            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 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 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.lang', true, 'INNER JOIN')
                        ->joinWith('lang', true, 'INNER JOIN');
        }
        
        public function getProductSpec()
        {
            return $this->hasOne(ProductSpec::className(), [ 'product_id' => 'product_id' ]);
        }
        
        public function getProductCertificates()
        {
            return $this->hasMany(ProductCertificate::className(), [ 'product_id' => 'product_id' ]);
        }
    }
