<?php

namespace Hura8\Components\ConfigGroup\Model;


use Hura8\Components\Product\Model\ProductModel;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;


class ConfigGroupModel extends aEntityBaseModel
{

    protected $tb_config_group                   = "";
    protected $tb_config_group_product          = "tb_config_group_product";
    protected $tb_config_group_product_cache    = "tb_config_group_product_cache";
    protected $tb_config_group_attribute        = "tb_config_group_attribute";
    protected $tb_config_group_attribute_value  = "tb_config_group_attribute_value";


    public function __construct() {
        parent::__construct('config_group');
        $this->tb_config_group = $this->tb_entity;
    }


    protected function extendedFilterOptions() : array
    {
        return [
            // empty for now
        ];
    }


    protected function updateGroupAttributeCount($group_id) {
        $this->db->runQuery(
            "UPDATE `".$this->tb_config_group."` SET 
                        `attribute_count` = (  SELECT COUNT(*) FROM `".$this->tb_config_group_attribute."` WHERE `group_id` = ?  )  
                    WHERE `id` = ?  LIMIT 1 ",
            ['d', 'd'], [ $group_id, $group_id ]
        );
    }


    protected function updateGroupProductCount($group_id) {
        $this->db->runQuery(
            "UPDATE `".$this->tb_config_group."` SET 
                        `item_count` = (  SELECT COUNT(*) FROM `".$this->tb_config_group_product."` WHERE `group_id` = ?  )  
                    WHERE `id` = ?  LIMIT 1 ",
            ['d', 'd'], [ $group_id, $group_id ]
        );
    }


    //attribute value
    public function deleteAttributeValue($att_value_id) {

        $attr_id = 0;
        $query = $this->db->runQuery("SELECT `attr_id` FROM `".$this->tb_config_group_attribute_value."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $att_value_id ]);
        if ($info = $this->db->fetchAssoc($query)) {
            $attr_id = $info['attr_id'];
        }

        $group_id = $this->getGroupIdFromAttribute($attr_id);

        $this->db->runQuery("DELETE FROM `".$this->tb_config_group_attribute_value."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $att_value_id ]);

        $this->resetProductConfigCache($group_id);

        $this->updateAttributeValueCount($attr_id);
    }


    protected function updateAttributeValueCount($attr_id) {
        $this->db->runQuery(
            "UPDATE `".$this->tb_config_group_attribute."` SET 
                        `value_count` = (  SELECT COUNT(*) FROM `".$this->tb_config_group_attribute_value."` WHERE `attr_id` = ?  )  
                    WHERE `id` = ?  LIMIT 1 ",
            ['d', 'd'],
            [$attr_id, $attr_id ]
        );
    }


    public function updateAttributeValue($id, $info) {

        $updated_info = $info;

        $updated_info['last_update'] = CURRENT_TIME;
        $updated_info['last_update_by'] = ADMIN_NAME;

        $this->db->update(
            $this->tb_config_group_attribute_value,
            $updated_info,
            [
                "id" => $id,
            ]
        );

        $group_id = $this->getGroupIdFromAttributeValue($id);
        $this->resetProductConfigCache($group_id);
    }


    public function createAttributeValue($info) {
        $updated_info = $info;

        $updated_info['create_time'] = CURRENT_TIME;
        $updated_info['create_by'] = ADMIN_NAME;
        $updated_info['last_update'] = CURRENT_TIME;
        $updated_info['last_update_by'] = ADMIN_NAME;

        $this->db->insert($this->tb_config_group_attribute_value, $updated_info );

        $group_id = $this->getGroupIdFromAttribute($info['attr_id']);
        $this->resetProductConfigCache($group_id);

        $this->updateAttributeValueCount($info['attr_id']);
    }

    //attribute
    public function deleteAttribute($id, $group_id = 0) {
        if(!$group_id) $group_id = $this->getGroupIdFromAttribute($id);
        $this->db->runQuery("DELETE FROM `".$this->tb_config_group_attribute."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $id ]);
        $this->db->runQuery("DELETE FROM `".$this->tb_config_group_attribute_value."` WHERE `attr_id` = ? LIMIT 1 ", ['d'], [ $id ]);

        $this->updateGroupAttributeCount($group_id);

        //todo: update for product attribute_config ?
        $this->resetProductConfigCache($group_id);
    }

    public function updateAttribute($id, $info) {

        $updated_info = $info;

        $updated_info['last_update'] = CURRENT_TIME;
        $updated_info['last_update_by'] = ADMIN_NAME;

        $this->db->update(
            $this->tb_config_group_attribute,
            $updated_info,
            [
                'id' => $id,
            ]
        );

        $group_id = $this->getGroupIdFromAttribute($id);
        $this->resetProductConfigCache($group_id);
    }

    public function createAttribute($info) {

        $updated_info = $info;

        $updated_info['create_time'] = CURRENT_TIME;
        $updated_info['create_by'] = ADMIN_NAME;
        $updated_info['last_update'] = CURRENT_TIME;
        $updated_info['last_update_by'] = ADMIN_NAME;

        $this->db->insert($this->tb_config_group_attribute, $updated_info );

        $this->resetProductConfigCache($info['group_id']);

        $this->updateGroupAttributeCount($info['group_id']);

        return  $this->db->get_insert_id();
    }

    private function getGroupIdFromAttributeValue($att_value_id) {
        $attr_id = 0;
        $query = $this->db->runQuery("SELECT `attr_id` FROM `".$this->tb_config_group_attribute_value."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $att_value_id ]);
        if ($info = $this->db->fetchAssoc($query)) {
            $attr_id = $info['attr_id'];
        }

        return $this->getGroupIdFromAttribute($attr_id);
    }

    private function getGroupIdFromAttribute($attr_id) {
        $group_id = 0;
        $query = $this->db->runQuery("SELECT `group_id` FROM `".$this->tb_config_group_attribute."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $attr_id ]);
        if ($info = $this->db->fetchAssoc($query)) {
            $group_id = $info['group_id'];
        }

        return $group_id;
    }

    //create or update product in a group
    public function createProduct($product_id, $group_id, array $attribute_config) {
        if($this->isProductInGroup($product_id, $group_id)) {

            $this->updateProduct($product_id, $group_id, $attribute_config);

        }else {

            $updated_info = [
                "product_id"        => $product_id,
                "group_id"          => $group_id,
                "attribute_config"  => json_encode($attribute_config),

                "create_time"          => CURRENT_TIME,
                "create_by"          => ADMIN_NAME,
                "last_update"          => CURRENT_TIME,
                "last_update_by"          => ADMIN_NAME,
            ];

            $this->db->insert($this->tb_config_group_product, $updated_info );

            $this->updateGroupProductCount($group_id);

        }

        $this->resetProductConfigCache($group_id);
    }

    public function deleteProduct($product_id, $group_id) {
        $this->db->runQuery(
            "DELETE FROM `".$this->tb_config_group_product."` WHERE `product_id` = ? AND `group_id` = ?  LIMIT 1 ",
            ['d', 'd'], [ $product_id, $group_id ]
        );

        $this->deleteProductConfigCache($product_id);

        $this->updateGroupProductCount($group_id);
    }

    public function updateProduct($product_id, $group_id, array $attribute_config, $product_name_in_group = '') {

        $this->db->update(
            $this->tb_config_group_product,
            [
                "attribute_config" => json_encode($attribute_config),
                "product_name_in_group" => substr($product_name_in_group, 0, 140),
                "last_update" => CURRENT_TIME,
                "last_update_by" => ADMIN_NAME,
            ],
            [
                "product_id" => $product_id,
                "group_id" => $group_id,
            ]
        );

        $this->resetProductConfigCache($group_id);

        return true;
    }


    //we want to reset all caches for products in a group
    //we need to do this when we make changes to group's attributes, or create new products/ update product in group
    protected function resetProductConfigCache($group_id) {
        $query = $this->db->runQuery("SELECT `product_id` FROM `".$this->tb_config_group_product."` WHERE `group_id` = ? ", ['d'], [$group_id]) ;
        $product_list = array();
        foreach( $this->db->fetchAll($query) as $item ){
            $product_list[] = $item['product_id'];
        }

        if(sizeof($product_list)) {
            $this->db->query("UPDATE `".$this->tb_config_group_product_cache."` SET 
                                          `value` = NULL 
                              WHERE `product_id` IN (".join(",", $product_list).") ") ;
        }
    }


    protected function deleteProductConfigCache($product_id) {
        $this->db->runQuery("DELETE FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` = ? LIMIT 1 ", ['d'], [$product_id]) ;
    }


    public function saveProductConfigCache($product_id, $value) {

        $query = $this->db->runQuery(
            "SELECT `product_id` FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` = ? LIMIT 1 ",
            ['d'], [$product_id]
        ) ;

        if($this->db->fetchAssoc($query)){
            $this->db->runQuery(
                "UPDATE `".$this->tb_config_group_product_cache."` SET 
                                  `value` = '".$this->db->escape(json_encode($value))."' 
                              WHERE `product_id` = ? LIMIT 1 ",
                ['d'], [$product_id]
            ) ;
        }else{
            $this->db->runQuery("INSERT INTO `".$this->tb_config_group_product_cache."` (`product_id`, `value`) 
                              VALUES ('". (int) $product_id."', '".$this->db->escape(json_encode($value))."') ") ;
        }
    }


    public function getProductConfigCache($product_id) {
        $query = $this->db->runQuery("SELECT `value` FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` = ? LIMIT 1 ", ['d'], [$product_id]) ;
        if($item_info = $this->db->fetchAssoc($query)){
            return ($item_info['value']) ? \json_decode($item_info['value'], true) : false;
        }

        return false;
    }


    //get all group config
    public function getGroupConfig($group_id) {

        $query = $this->db->runQuery(
            "SELECT 
                       a.id AS attribute_id , 
                       a.name AS attribute_name , 
                       a.ordering AS attr_ordering ,
                       v.id AS value_id , 
                       v.name AS value_name , 
                       v.image AS image , 
                       v.color_code AS color , 
                       v.ordering , 
                       v.description AS description
                   FROM `".$this->tb_config_group_attribute."` a
                   LEFT JOIN `".$this->tb_config_group_attribute_value."` v ON a.id = v.attr_id
                   WHERE a.group_id = ?
                   ORDER BY attr_ordering DESC, `ordering` DESC
                 ",
            ['d'], [$group_id]
        );

        $group_attribute = array();
        foreach ( $this->db->fetchAll($query) as $info ) {
            if(!isset($group_attribute[$info['attribute_id']])) {
                $group_attribute[$info['attribute_id']] = array(
                    'id'    => $info['attribute_id'],
                    'name' => $info['attribute_name'],
                    'ordering' => $info['attr_ordering'],
                    'list' => array(),
                );
            }

            if($info['value_id']) {
                $group_attribute[$info['attribute_id']]['list'][] = array(
                    'id' => $info['value_id'],
                    'name' => $info['value_name'],
                    'image' => $info['image'],
                    'color' => $info['color'],
                    'ordering' => $info['ordering'],
                    'description' => $info['description'],
                );
            }
        }

        return $group_attribute;
    }


    public function getProductConfigGroupId($product_id) {
        $query = $this->db->runQuery(
            "SELECT `group_id` FROM `".$this->tb_config_group_product."`  WHERE `product_id` = ? LIMIT 1 ",
            ['d'], [$product_id]
        ) ;

        if($item_info = $this->db->fetchAssoc($query)){
            return $item_info['group_id'];
        }

        return 0;
    }


    public function getProductInGroup($group_id){
        $query = $this->db->runQuery(
            "SELECT  `product_id`, `product_name_in_group`, `attribute_config`
                                           FROM `".$this->tb_config_group_product."`
                                           WHERE `group_id` = ?
                                    ",
            ['d'], [$group_id]
        );

        $product_list = array();
        $product_ids = array();

        foreach ( $this->db->fetchAll($query) as $info ) {
            $product_ids[] = $info['product_id'];

            $product_list[$info['product_id']] = array(
                "id"            => $info['product_id'],
                "name"          => "",
                "product_name_in_group" => $info['product_name_in_group'],
                "attribute"     => \json_decode($info['attribute_config'], true),
                "url"           => "",
                "sku"           => "",
                "price"         => 0,
                "image"         => "",
                "status"         => "",
            );
        }

        //find product urls
        if(sizeof($product_ids)) {
            $objProductModel = new ProductModel();
            $product_list_info = $objProductModel->getListByIds($product_ids);

            // debug_var($product_list_info);
            // update $product_list
            foreach ($product_list as $_pro_id => $_info) {
                $_pro_info = $product_list_info[$_pro_id] ?? null;
                if($_pro_info) {
                    $product_list[$_pro_id]['name'] = $_pro_info['title'];
                    $product_list[$_pro_id]['price'] = $_pro_info['price'];
                    $product_list[$_pro_id]['sku'] = $_pro_info['sku'];
                    $product_list[$_pro_id]['image'] = $_pro_info['thumbnail'];
                    $product_list[$_pro_id]['url'] = $_pro_info['request_path'];
                    $product_list[$_pro_id]['status'] = $_pro_info['status'];
                }
            }
        }

        return $product_list;
    }


    protected function isProductInGroup($product_id, $group_id) {
        $query = $this->db->runQuery(
            "SELECT * FROM `".$this->tb_config_group_product."` WHERE `product_id` = ? AND `group_id` = ? LIMIT 1 ",
            ['d', 'd'],
            [$product_id, $group_id]
        ) ;

        return ($this->db->fetchAssoc($query));
    }


    protected function _buildQueryConditionExtend(array $filter_condition) : ?array
    {
        /*$condition = array(
            "q" => "",
            "numPerPage" => 20,
            "order_by" => '',
        );*/

        $catCondition = "";

        return [
            $catCondition,
            [],
            []
        ];
    }

    protected function beforeCreateItem(array $input_info): AppResponse
    {
        $info = $input_info;

        $info['create_time'] = CURRENT_TIME;
        $info['create_by'] = ADMIN_NAME;
        $info['last_update'] = CURRENT_TIME;
        $info['last_update_by'] = ADMIN_NAME;

        return new AppResponse('ok', null, $info);
    }

    protected function afterCreateItem($new_item_id, $new_item_info)
    {
        // TODO: Implement afterCreateItem() method.
    }

    protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info):AppResponse
    {
        $info = $new_input_info;

        $info['last_update'] = CURRENT_TIME;
        $info['last_update_by'] = ADMIN_NAME;

        return new AppResponse('ok', null, $info);
    }

    protected function afterUpdateItem($item_id, $old_item_info, $new_item_info)
    {
        // TODO: Implement afterUpdateItem() method.
    }

    protected function beforeDeleteItem($item_id, $item_info):AppResponse
    {
        return new AppResponse('ok' );
    }

    protected function afterDeleteItem($item_id, $item_info)
    {

        $query = $this->db->runQuery("SELECT `id` FROM `".$this->tb_config_group_attribute."` WHERE `group_id` = ? ", ['d'], [$item_id]);

        foreach ( $this->db->fetchAll($query) as $info ) {
            $this->deleteAttribute($info['id'], $item_id);
        }

        $this->db->runQuery(
            "DELETE FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` IN (SELECT product_id FROM config_group_product WHERE `group_id` = ? ) ",
            ['d'], [$item_id]
        ) ;

        $this->db->runQuery("DELETE FROM `".$this->tb_config_group_product."` WHERE `group_id` = ? ", ['d'], [$item_id]) ;
    }
}
