<?php

namespace MicroweberPackages\Category\HelperRenders;

use MicroweberPackages\Category\Models\Category;
use function Opis\Closure\serialize as serializeClosure;

class CategoryTreeData
{

    /** @var \MicroweberPackages\App\LaravelApplication */
    public $app;


    public function __construct($app = null)
    {
        if (is_object($app)) {
            $this->app = $app;
        } else {
            $this->app = mw();
        }
    }


    public function get($params)
    {
        $p2 = array();
        if (!is_array($params)) {
            if (is_string($params)) {
                parse_str($params, $p2);
                $params = $p2;
            }
        }
        if (isset($params['parent'])) {
            $parent = ($params['parent']);
        } elseif (isset($params['subtype_value'])) {
            $parent = ($params['subtype_value']);
        } else {
            $parent = 0;
        }

        //asort($params);
        $function_cache_id = false;
        //$function_cache_id = __FUNCTION__ . crc32(serializeClosure($params));
         $active_cat = false;
        if (defined('CATEGORY_ID')) {
        //    $function_cache_id .= CATEGORY_ID;
            $active_cat = CATEGORY_ID;
        }

        $cat_url = $this->app->category_manager->get_category_id_from_url();
        if ($cat_url != false) {
          //  $function_cache_id .= $cat_url;
            $active_cat = $cat_url;
        } else {
            $cat_url = $this->app->url_manager->param('categories', true);
            if ($cat_url != false) {
          //      $function_cache_id .= $cat_url;
            }
        }

        $cache_group = 'categories/global';
        if (isset($params['nest_level'])) {
            $depth_level_counter = $params['nest_level'];
        } else {
            $depth_level_counter = 0;
        }
        $nest_level_orig = $depth_level_counter;


        if (isset($params['remove_ids'])) {
            $remove_ids = $params['remove_ids'];
        } else {
            $remove_ids = false;
        }


        if (isset($params['users_can_create_content'])) {
            $users_can_create_content = $params['users_can_create_content'];
        } else {
            $users_can_create_content = false;
        }

        if (isset($params['include_first'])) {
            $include_first = $params['include_first'];
        } else {
            $include_first = false;
        }

        if (isset($params['content_type'])) {
            $content_type = $params['content_type'];
        } else {
            $content_type = false;
        }

        if (isset($params['add_ids'])) {
            $add_ids = $params['add_ids'];
        } else {
            $add_ids = false;
        }

        if (isset($params['orderby'])) {
            $orderby = $params['orderby'];
        } else {
            $orderby = false;
        }

        $table = $this->app->category_manager->tables['categories'];
        if (isset($params['content_id'])) {
            $params['for_page'] = $params['content_id'];
        }
        if (isset($params['content_id'])) {
            $params['for_page'] = $params['content_id'];
        }

        if (isset($params['for_page']) and $params['for_page'] != false) {
            $page = $this->app->content_manager->get_by_id($params['for_page']);

            if ($page and isset($page['subtype']) and isset($page['subtype_value']) and $page['subtype'] == 'dynamic' and intval($page['subtype_value']) > 0) {
                $parent = $page['subtype_value'];
            } else {
                $params['rel_type'] = 'content';
                $params['rel_id'] = $params['for_page'];
                $parent = 0;
            }
        }
        $active_code_tag = false;
        if (isset($params['active_code_tag']) and $params['active_code_tag'] != false) {
            $active_code_tag = $params['active_code_tag'];
        }

        if (isset($params['subtype_value']) and $params['subtype_value'] != false) {
            $parent = $params['subtype_value'];
        }
         $skip123 = false;
        $fors = array();
        if (isset($params['parent']) and $params['parent'] != false) {
            $parent = intval($params['parent']);

        } else {
            if (!isset($params['for'])) {
                $params['for'] = 'content';
            }

            if (!isset($params['content_id']) and isset($params['for']) and $params['for'] != false) {
                $table_assoc_name = $this->app->database_manager->assoc_table_name($params['for']);
                $skip123 = true;
                $str0 = 'no_cache=true&is_deleted=0&orderby=position asc&table=' . $table . '&limit=1000&data_type=category&what=categories&' . 'parent_id=0&rel_type=' . $table_assoc_name;
                $cat_get_params = array();
                $cat_get_params['is_deleted'] = 0;
                $cat_get_params['order_by'] = 'position asc';
                $cat_get_params['limit'] = '1000';
                $cat_get_params['data_type'] = 'category';
                $cat_get_params['no_cache'] = 1;
                $cat_get_params['parent_id'] = 0;
                $cat_get_params['table'] = $table;
                $cat_get_params['rel_type'] = $table_assoc_name;
                if(isset($params['filter'])){
                $cat_get_params['filter'] = $params['filter'];

                }
                if ($users_can_create_content != false) {
                    $cat_get_params['users_can_create_content'] = $users_can_create_content;
                }


                $fors = $this->app->database_manager->get($cat_get_params);
            }

            if (!isset($params['content_id']) and isset($params['try_rel_id']) and intval($params['try_rel_id']) != 0) {
                $skip123 = true;
                $str1 = 'no_cache=true&is_deleted=0&orderby=position asc&table=' . $table . '&limit=1000&parent_id=0&rel_id=' . $params['try_rel_id'];
                $fors1 = $this->app->database_manager->get($str1);
                if (is_array($fors1)) {
                    $fors = array_merge($fors, $fors1);
                }
            }
        }

        if (isset($params['not_for_page']) and $params['not_for_page'] != false) {
            $page = $this->app->content_manager->get_page($params['not_for_page']);
            $remove_ids = array($page['subtype_value']);
        }

        $max_level = false;
        if (isset($params['max_level'])) {
            $max_level = $params['max_level'];
        }

        $only_with_content = false;
        if (isset($params['only_with_content'])) {
            $only_with_content = $params['only_with_content'];
        }


        $visible_on_frontend = false;
        if (isset($params['visible_on_frontend'])) {
            $visible_on_frontend = $params['visible_on_frontend'];
        }

        $params['table'] = $table;
        if (is_string($add_ids)) {
            $add_ids = explode(',', $add_ids);
        }

        $tree_only_ids = false;

        if (isset($params['for-content-id'])) {
            $content_cats = $this->app->category_manager->get_for_content($params['for-content-id']);
            $fors = array();
            if (is_array($content_cats) and !empty($content_cats)) {
                if (!is_array($add_ids)) {
                    $add_ids = array();
                }
                foreach ($content_cats as $content_cat_item) {
                    if (isset($content_cat_item['id'])) {
                        $add_ids[] = $content_cat_item['id'];
                        $tree_only_ids[] = $content_cat_item['id'];
                    }
                }
            }
        } elseif (isset($params['rel_type']) and $params['rel_type'] != false and isset($params['rel_id'])) {
            $table_assoc_name = $this->app->database_manager->assoc_table_name($params['rel_type']);
            $skip123 = true;
            $users_can_create_content_q = false;
            $cat_get_params = array();
            $cat_get_params['is_deleted'] = 0;
            $cat_get_params['order_by'] = 'position asc';
            $cat_get_params['limit'] = '1000';
            $cat_get_params['data_type'] = 'category';
            $cat_get_params['rel_id'] = ($params['rel_id']);
            $cat_get_params['table'] = $table;
            $cat_get_params['rel_type'] = $table_assoc_name;
            if(isset($params['filter'])){
                $cat_get_params['filter'] = $params['filter'];
            }
            if (isset($parent) and $parent != false) {
                $page_for_parent = $this->app->category_manager->get_page($parent);
                $cats_for_content = $this->app->category_manager->get_for_content($params['rel_id']);
                if ($cats_for_content) {
                    foreach ($cats_for_content as $cat_for_content) {
                        if ($parent == $cat_for_content['id']) {
                            $cat_get_params['parent_id'] = $parent;
                            unset($cat_get_params['rel_type']);
                            unset($cat_get_params['rel_id']);

                        }
                    }
                }

            }
            if ($users_can_create_content != false) {
                $cat_get_params['users_can_create_content'] = $users_can_create_content;
            }

            $fors = $this->app->database_manager->get($cat_get_params);

        }

        $tree_data = array();
        if ($fors) {
            foreach ($fors as $cat) {

                if (isset($cat['id'])) {

                    if(isset($params['only_cats_with_active_products']) && $params['only_cats_with_active_products'] == true) {
                        //Skip those without products in them or their children
                        $hasActiveProducts = $this->hasActiveProductsInItsTree($cat['id']);
                        if($hasActiveProducts == false) {
                            continue;
                        }
                    }

                    $override = $this->app->event_manager->trigger('category.after.get', $cat);
                    if (is_array($override) && isset($override[0])) {
                        $cat = $override[0];
                    }

                    $tree = $this->_build_children_array($cat['id'],
                        $remove_ids,
                        $add_ids,
                        $include_first,
                        $content_type,
                        $orderby,
                        $only_with_content,
                        $visible_on_frontend,
                        $depth_level_counter = 0,
                        $max_level,
                        $only_ids= false,
                        $params
                    );

//                    if (isset($tree[0]) and $tree[0]['id'] == $cat['id']) {
//                        unset($tree[0]);
//                    }
                    if ($tree) {
                        $cat['children'] = $tree;
                    }
                    $tree_data[] = $cat;
                }
            }
        }

        if(isset($params['in_stock'])){
            $tree_data = $this->inStock($tree_data, $params['in_stock']);
        }

        return $tree_data;
    }

    private function inStock($treeData, $onlyCategoriesWithAviableProducts)
    {
        $originalTree = $treeData;

        foreach($treeData as $key => $category) {

            $check  = app()->category_repository->hasProductsInStock($category['id']);

           if($check && empty($category['children'])) {
             unset($originalTree[$key]);
           } else if(!empty($category['children'])) {
                foreach($category['children'] as $index => $cat) {
                    $childrenHasAviableProds = $this->childCategoriesHasAviableProducts($cat);
                    if($childrenHasAviableProds == false) {
                        unset($originalTree[$key]);
                        break;
                    }
                }
           }
        }

        if($onlyCategoriesWithAviableProducts) {
            return $originalTree;
        } else {
            return array_recursive_diff($treeData, $originalTree);
        }
    }

    private function childCategoriesHasAviableProducts($categoryData)
    {
        $check  = app()->category_repository->hasProductsInStock($categoryData['id']);
        if($check) {
            return true;
        } else if(!empty($categoryData['children'])) {
             foreach($categoryData['children'] as $index => $cat) {
                return $this->childCategoriesHasAviableProducts($cat);
             }
        } else {
            return false;
        }
    }




    private function _build_children_array($parent,
                                           $remove_ids = false,
                                           $add_ids = false,
                                           $include_first = false,
                                           $content_type = false,
                                           $orderby = false,
                                           $only_with_content = false,
                                           $visible_on_frontend = false,
                                           $depth_level_counter = 0,
                                           $max_level = false,
                                           $only_ids = false, $params = false)
    {


        if ($max_level != false and $depth_level_counter != false) {
            if (intval($depth_level_counter) >= intval($max_level)) {
                // return if max depth
                return;
            }
        }

         $db_t_content = $this->app->category_manager->tables['content'];

        $table = $db_categories = $this->app->category_manager->tables['categories'];
        $parent = intval($parent);

        $ids_add_q = array();
        $ids_remove_q = array();
        if ($parent) {
            $ids_remove_q = array($parent);
        }

//        if ($parent == false) {
//            $parent = (0);
//
//            $include_first = false;
//        } else {
//            $parent = intval($parent);
//        }

        if (!is_array($orderby)) {
            $orderby[0] = 'position';

            $orderby[1] = 'ASC';
        }

        if (isset($remove_ids) and !is_array($remove_ids)) {
            $temp = intval($remove_ids);
            $ids_remove_q[] = $temp;
        } elseif (is_array($remove_ids) and !empty($remove_ids)) {
            $ids_remove_q = array_merge($ids_remove_q, $remove_ids);
        }

        if (is_array($add_ids) and !empty($add_ids)) {
            $ids_add_q = array_merge($ids_add_q, $add_ids);
            $ids_add_q = array_filter($ids_add_q);
            $ids_add_q = array_map('intval', $ids_add_q);
        }


        $cat_get_params = array();
        $cat_get_params['is_deleted'] = 0;
        $cat_get_params['order_by'] = "{$orderby [0]} {$orderby [1]}";// blank spaces are important here !!!
        $cat_get_params['limit'] = '1000';
        $cat_get_params['table'] = $table;

        $cat_get_params['parent_id'] = $parent;
        if(isset($params['filter'])){
            $cat_get_params['filter'] = $params['filter'];

        }
        $cat_get_params['loop_fix_q'] = function ($query) use ($table, $parent) {
            // there is bug on postgres:  Invalid text representation: 7 ERROR: invalid input syntax for integer: "categories.parent_id"
            // $query = $query->where($table . '.id', '!=', $table . '.parent_id');

            $query = $query->where($table . '.id', '!=', $parent);
            return $query;
        };

        if ($ids_add_q) {

            $cat_get_params['add_ids_q'] = function ($query) use ($ids_add_q) {

                $query = $query->whereIn('id', $ids_add_q);

                return $query;
            };

        }

        if ($ids_remove_q and !empty($ids_remove_q)) {

            $cat_get_params['remove_ids_q'] = function ($query) use ($ids_remove_q) {
                $query = $query->whereNotIn('id', $ids_remove_q);
                return $query;
            };
        }
//dump($cat_get_params);
        $result = $this->app->database_manager->get($cat_get_params);

        $output = '';


        $only_with_content2 = $only_with_content;
        if (isset($remove_ids) and !is_array($remove_ids)) {
            $remove_ids = array(intval($remove_ids));
        }

        if (isset($result) and is_array($result) and !empty($result)) {
            $return = array();
            ++$depth_level_counter;
            $i = 0;
            foreach ($result as $item) {

                if(isset($params['only_cats_with_active_products']) && $params['only_cats_with_active_products'] == true) {
                    //Skip those without products in them or their children
                    $hasActiveProducts = $this->hasActiveProductsInItsTree($item['id']);
                    if($hasActiveProducts == false) {
                        continue;
                    }
                }

                $override = $this->app->event_manager->trigger('category.after.get', $item);
                if (is_array($override) && isset($override[0])) {
                    $item = $override[0];
                }

                $id = intval($item['id']);
                $remove_ids[] = $id;

                $item['children'] = $this->_build_children_array($id, $remove_ids, $add_ids, $include_first = false, $content_type, $orderby, $only_with_content, $visible_on_frontend, $depth_level_counter, $max_level, $only_ids,$params);
                $return[] = $item;
            }
            return $return;

        } else {
            return false;
        }
    }

    private function hasActiveProductsInItsTree($catId)
    {
        $catObj = \MicroweberPackages\Category\Models\Category::find($catId);
        $hasActiveProducts = \MicroweberPackages\Category\Models\Category::hasActiveProductInSubcategories($catObj);

        return $hasActiveProducts;
    }

}


