<?php

namespace Hura8\System\Controller;

use Hura8\Interfaces\AppResponse;
use Hura8\Interfaces\iEntityCategoryModel;
use Hura8\Interfaces\iEntityLanguageModel;
use Hura8\Traits\ClassCacheTrait;

abstract class aCategoryBaseController
{

    use ClassCacheTrait;

    /* @var iEntityCategoryModel $iEntityCategoryModel */
    protected $iEntityCategoryModel;

    /* @var ?iEntityLanguageModel $iEntityLanguageModel */
    protected $iEntityLanguageModel = null;

    protected $view_language = LANGUAGE;

    public static $public_fields = [
        "id", "title", "cat_path", "request_path", "image", "url", "not_translated", "children"
    ];

    public function __construct(
        iEntityCategoryModel $iEntityCategoryModel,
        ?iEntityLanguageModel $iEntityLanguageModel = null
    ) {
        $this->iEntityCategoryModel = $iEntityCategoryModel;

        if(!$this->isDefaultLanguage() && $iEntityLanguageModel instanceof iEntityLanguageModel) {
            $this->iEntityLanguageModel = $iEntityLanguageModel;
            $this->iEntityLanguageModel->setLanguage($this->view_language);
        }
    }


    public function create(array $info) : AppResponse
    {
        return $this->iEntityCategoryModel->create($info);
    }


    public function update($id, array $info) : AppResponse
    {
        if($this->iEntityLanguageModel) {
            return $this->iEntityLanguageModel->update($id, $info, $info['title']);
        }

        return $this->iEntityCategoryModel->update($id, $info);
    }


    public function delete($id) : AppResponse
    {
        return $this->iEntityCategoryModel->delete($id);
    }


    public function updateFields($id, array $info) : AppResponse
    {
        return $this->iEntityCategoryModel->updateFields($id, $info);
    }


    public function isDefaultLanguage() : bool
    {
        return IS_DEFAULT_LANGUAGE;
    }


    public function getListByIds(array $list_id, array $condition = array()) : array
    {
        $item_list = $this->iEntityCategoryModel->getListByIds($list_id, $condition);

        if($this->iEntityLanguageModel) {
            $item_list_language_info = $this->iEntityLanguageModel->getListByIds($list_id);

            $final_list = [];
            foreach ($item_list as $item) {
                $item_language_info = $item_list_language_info[$item['id']] ?? ["not_translated" => true];
                $final_list[] = $this->formatItemInList(array_merge($item, $item_language_info));
            }

            return $final_list;
        }

        return array_map(function ($item){
            return $this->formatItemInList($item);
        }, $item_list);
    }


    protected function formatItemInList(array $info): array
    {
        return $info;
    }


    public function getActualFilterCondition(array $raw_filter_condition) : array
    {
        return $raw_filter_condition;
    }


    public function getModelFilterCondition(array $raw_filter_condition) : array
    {
        return $this->iEntityCategoryModel->getQueryCondition( $raw_filter_condition);
    }


    public function getList(array $condition) : array
    {
        $item_list = $this->iEntityCategoryModel->getList($condition);

        if($this->iEntityLanguageModel) {
            $list_ids = array_map(function ($item){ return $item['id'];}, $item_list);
            $item_list_language_info = $this->iEntityLanguageModel->getListByIds($list_ids);

            $final_list = [];
            foreach ($item_list as $item) {
                $item_language_info = $item_list_language_info[$item['id']] ?? ["not_translated" => true];
                $final_list[] = $this->formatItemInList(array_merge($item, $item_language_info));
            }

            return $final_list;
        }

        return array_map(function ($item){
            return $this->formatItemInList($item);
        }, $item_list);
    }


    public function getTotal(array $condition) : int
    {
        return $this->iEntityCategoryModel->getTotal($condition);
    }


    protected function formatItemInfo(?array $info) : ?array
    {
        return $info;
    }


    public function getInfo($id) : ?array
    {
        if(!$id) return null;

        return self::getCache("getInfo-".$id."-".$this->view_language, function () use ($id){

            if($this->iEntityLanguageModel) {
                $info = $this->iEntityCategoryModel->getInfo($id);
                $item_language_info = $this->iEntityLanguageModel->getInfo($id);
                if($item_language_info) {
                    return $this->formatItemInfo(array_merge($info, $item_language_info));
                }
            }

            return $this->formatItemInfo($this->iEntityCategoryModel->getInfo($id));

        });
    }


    public function getEmptyInfo(array $additional_fields = []) : array
    {
        return $this->iEntityCategoryModel->getEmptyInfo($additional_fields);
    }


    // all categories and nested by parent
    public function getNestedCategories($is_public = false) {

        $cache_key = "getNestedCategories-".$this->iEntityCategoryModel->getEntityType()."-".($is_public ? 1: 0);

        return self::getCache($cache_key, function () use ($is_public){
            $all_categories = $this->getAllParent([
                'status' => ($is_public) ? 1 : 0
            ]);

            $result = [];
            if(isset($all_categories[0])) {
                foreach ($all_categories[0] as $index => $info) {
                    $info['children'] = ($info['is_parent']) ? $this->getChildren($info['id'], $all_categories, 1) : [];
                    $result[] = $this->formatItemInList($info);
                }
            }

            return $result;
        });

    }


    public function getChildren($parent_id, $all_categories, $current_level = 1){
        // dont allow too many nested level
        $max_deep_level_allow = 5;
        if($current_level == $max_deep_level_allow) return [];

        $result = [];
        if(isset($all_categories[$parent_id])) {
            foreach ($all_categories[$parent_id] as $id => $info) {
                $info['children'] = $this->getChildren($id, $all_categories, $current_level + 1);
                $result[] = $this->formatItemInList($info);
            }
        }

        return $result;
    }


    public function showPath($catPathId, $p_category){

        if(!$catPathId){
            $cat_info = $this->getInfo($p_category);
            $catPathId = $cat_info['cat_path'];
        }

        $result = array();
        $path_build = array();

        if(strlen($catPathId) > 0){
            $cat_id_list = array_filter(explode(":", $catPathId));

            $cat_list_info = $this->getListByIds($cat_id_list);

            //reverse cat id order because the parent in the right most
            krsort($cat_id_list);

            $start_count = 0;
            $count_cat = sizeof($cat_id_list);

            foreach($cat_id_list as $catId){

                $_cat_info = $cat_list_info[$catId] ?? null;
                if(!$_cat_info) continue;

                $start_count ++;
                $path_build[] = "<a href=\"".$_cat_info['url']."\">".$_cat_info['title']."</a> ";

                $result[] = array(
                    'id' 	    => $catId,
                    'url' 	    => $_cat_info['url'],
                    'title' 	=> $_cat_info['title'],
                );

                if($start_count < $count_cat) $path_build[] = " &gt;&gt; ";
            }
        }

        return array(
            'path' => $result,
            'path_url' => join("", $path_build),
        );
    }


    public function getAll(array $condition = []) {
        return $this->iEntityCategoryModel->getAll($condition);
    }


    public function getAllParent(array $condition = []) {

        if($this->iEntityLanguageModel) {

            $all_categories = $this->getAll($condition);

            $item_list_ids = array_map(function ($item){ return $item['id']; }, $all_categories);
            $item_list_language_info = $this->iEntityLanguageModel->getListByIds($item_list_ids);

            $translated_list = [];
            foreach ($all_categories as $item) {
                $item_language_info = $item_list_language_info[$item['id']] ?? ["not_translated" => true];
                $item = array_merge($item, $item_language_info);

                $translated_list[] = array_merge($item, $item_language_info);
            }

            // get group by parent
            $final_list = [];
            foreach ( $translated_list as $item ) {
                $final_list[$item['parent_id']][$item['id']] = $this->formatItemInList($item);
            }

            return $final_list;
        }

        // else
        $all_categories = $this->getAll($condition);
        $final_list = [];
        foreach ( $all_categories as $item ) {
            $final_list[$item['parent_id']][$item['id']] = $this->formatItemInList($item);
        }

        return $final_list;
    }


}
