<?php
namespace common\libs\dataList;

use backendApi\modules\v1\models\Admin;
use backendApi\modules\v1\models\AdminRole;
use common\components\Model;
use common\helpers\Tool;
use yii\base\Exception;

/**
 * Class DataList
 * @package common\libs\dataList
 * @method getListName
 * 列表名称
 * @method dataHandle
 * 需要子类继承的方法实现数据的获取
 * @method getColumn
 * 需要子类继承的方法实现column的获取
 * 传null是指：这种传输方式主要是用于索引，因为过滤后的字段可能没有这种ID，但是一些功能的操作还需要用这种ID去关联，例如前台会员列表中的勾选批量状态管理，这里需要的就是USER_ID
 * 例如：
 * $this->columns = [
 *      'USER_ID' => null,
 *      'USER_NAME' => [
 *          'header' => '会员编号',
 *          'headerOther' => ['width' => '150'],
 *      ],
 *      'IS_DEC' => [
 *          'header' => '是否报单中心',
 *          'value' => function($row) {
 *              return (new YesNo([
 *                  'value' => $row['IS_DEC'],
 *              ]))->result();
 *          },
 *          'show' => function($row) {
 *              return '<div>列表展示的值结果</div>';
 *          }
 *          'headerOther' => function($row) {
 *              return [
 *                  'width' => '120',
 *                  'tag'=>['type'=>$row['IS_DEC'] ? 'success' : 'info', 'size' => 'small']
 *              ];
 *          },
 *      ],
 * ]
 * @method getFilterTypes
 */
class DataList extends Model
{
    /**
     * 导出
     * @var bool
     */
    public $isExport = false;
    /**
     * 列表当前页码
     * @var null
     */
    protected $page = null;
    /**
     * 列表每页数量
     * @var int
     */
    protected $pageSize = 0;
    /**
     * 列表查询条件
     * @var string
     */
    protected $condition = '';
    /**
     * 列表查询条件参数
     * @var array
     */
    protected $params = [];
    /**
     * 列表查询其他参数
     * @var array
     */
    protected $others = [];
    /**
     * 列表数据
     * @var
     */
    protected $listData;
    /**
     * 列表字段限制条件
     * @var
     */
    protected $columns;
    /**
     * 用于筛选的字段
     * @var
     */
    protected $filterTypes;
    /**
     * 主要是给导出时候的表头使用
     * @var array
     */
    protected $headers = [];
    /**
     * 主要是给页面输出是展示用的就是columns去掉value的结果，让vue方便循环表头和表头样式
     * @var array
     */
    protected $columnsShow = [];
    /**
     * 主要是给前端的筛选类型
     * @var array
     */
    protected $filterTypesShow = [];

    /**
     * 获取列表
     * @param null $params
     * @return mixed
     * @throws Exception
     */
    public function getList($params = null){

        if($params !== null) {

            $this->prepare($params);
        }
        // 获取数据
        $this->dataHandle();
        // 获取列信息
        $this->getColumn();
        // 获取筛选字段的信息，用于前端筛选
        if(!$this->isExport){
            $this->getFilterTypes();
        }
        // 利用权限处理掉不需要的字段（只需要从$this->columns中去掉就可以）
        $userId = isset($params['userId']) && $params['userId'] ? $params['userId'] : null;
        $this->permissionColumn($userId);
        // 处理数据
        $this->_formatDataByColumn();
        return $this->listData;
    }

    /**
     * 获取导出用到的列标题
     * @param $userId
     * @return array
     * @throws Exception
     */
    public function getExportHeaders($userId){
        if(!$this->headers && $this->isExport){
            $this->getColumn();
            // 利用权限处理掉不需要的字段（只需要从$this->columns中去掉就可以）
            $this->permissionColumn($userId);
            foreach($this->columns as $hk => $column){
                if(is_string($column)){
                    $this->headers[] = Tool::textConvert($column);
                } elseif(is_array($column)) {
                    if(!isset($column['header'])){
                        throw new Exception('column数组中必须存在header');
                    }
                    if(isset($column['hidden'])&&$column['hidden']) continue;
                    if(is_callable($column['header'])){
                        $header = $column['header']([]);
                    } else {
                        $header = $column['header'];
                    }
                    $this->headers[] = Tool::textConvert($header);
                } elseif (is_callable($column)) {
                    $this->headers[] = Tool::textConvert($column([]));
                }
            }
        }
        return $this->headers;
    }

    /**
     * 获取全部列及列名，主要用于后台权限的筛选
     * @return array
     * @throws Exception
     */
    public function getAllColumnHeaderName(){
        $result = [];
        foreach($this->getColumn() as $hk => $column){
            if(is_string($column)){
                $result[] = [
                    'header' => $column,
                    'index' => $hk,
                ];
            } elseif(is_array($column)) {
                if(!isset($column['header'])){
                    throw new Exception('column数组中必须存在header');
                }
                //if(isset($column['hidden'])&&$column['hidden']) continue;
                if(is_callable($column['header'])){
                    $header = $column['header']([]);
                } else {
                    $header = $column['header'];
                }
                $result[] = [
                    'header' => $header,
                    'index' => $hk,
                ];
            } elseif (is_callable($column)) {
                $result[] = [
                    'header' => $column([]),
                    'index' => $hk,
                ];
            }
        }
        return $result;
    }

    /**
     * 整理参数
     * @param $params
     */
    protected function prepare($params){
        $default = [
            'condition' => '',
            'params' => [],
            'others' => [],
            'page' => null,
            'pageSize' => 0,
        ];
        $params = Tool::deepParse($params ,$default);
        $this->condition = $params['condition'];
        $this->params = $params['params'];
        $this->others = $params['others'];
        $this->page = $params['page'];
        $this->pageSize = $params['pageSize'];
    }

    /**
     * 格式化输出的数据
     * @throws Exception
     */
    private function _formatDataByColumn(){
        $data = [];
        foreach($this->listData['list'] as $key=>$row){
            foreach($this->columns as $hk => $column){
                if(is_string($column)){
                    if($key == 0){
                        $this->headers[] = $this->isExport ? Tool::textConvert($column) : $column;
                        $this->columnsShow[] = [
                            'header' => $column,
                            'index' => $hk,
                            'other' => [],
                        ];
                        if(isset($this->filterTypes[$hk])){
                            $this->filterTypesShow[$hk] = $this->filterTypes[$hk];
                        }
                    }
                    if($this->isExport){
                        $data[$key][$hk] = $row[$hk];
                    } else {
                        $data[$key][$hk] = [
                            'value' => $row[$hk],
                            'other' => [],
                        ];
                    }
                } elseif(is_array($column)) {
                    if(!isset($column['header'])){
                        throw new Exception('column数组中必须存在header');
                    }
                    if($key == 0){
                        if(!isset($column['hidden']) || !$column['hidden']){
                            if(is_callable($column['header'])){
                                $header = $column['header']($row);
                            } else {
                                $header = $column['header'];
                            }
                            if(isset($column['headerOther'])){
                                if(is_callable($column['headerOther'])){
                                    $headerOther = $column['headerOther']($row);
                                } else {
                                    $headerOther = $column['headerOther'];
                                }
                            } else {
                                $headerOther = [];
                            }
                            $this->headers[] = $this->isExport ? Tool::textConvert($header) : $header;
                            $this->columnsShow[] = [
                                'header' => $header,
                                'index' => $hk,
                                'other' => $headerOther,
                            ];
                        }
                        if(isset($this->filterTypes[$hk])){
                            $this->filterTypesShow[$hk] = $this->filterTypes[$hk];
                        }
                    }
                    if(isset($column['hidden'])&&$column['hidden']) continue;
                    // 如果是回调函数，则直接调用回调函数，否则直接赋值
                    $tempValue = null;
                    if(!isset($column['value'])){
                        $tempValue = $row[$hk];
                    } else {
                        if(is_callable($column['value'])){
                            $tempValue = $column['value']($row);
                        } else {
                            $tempValue = $column['value'];
                        }
                    }
                    if(!$this->isExport && isset($column['showValue'])){
                        if(is_callable($column['showValue'])){
                            $tempValue = $column['showValue']($row);
                        } else {
                            $tempValue = $column['showValue'];
                        }
                    }
                    if(!isset($column['valueOther'])){
                        $tempListValueOther = [];
                    } else {
                        if(is_callable($column['valueOther'])){
                            $tempListValueOther = $column['valueOther']($row);
                        } else {
                            $tempListValueOther = $column['valueOther'];
                        }
                    }
                    if($this->isExport){
                        $data[$key][$hk] = $tempValue;
                    } else {
                        $data[$key][$hk] = [
                            'value' => $tempValue,
                            'other' => $tempListValueOther,
                        ];
                    }
                } elseif (is_callable($column)) {
                    if($key == 0){
                        $this->headers[] = $this->isExport ? Tool::textConvert($column($row)) : $column($row);
                        $this->columnsShow[] = [
                            'header' => $column($row),
                            'index' => $hk,
                            'other' => [],
                        ];
                        if(isset($this->filterTypes[$hk])){
                            $this->filterTypesShow[$hk] = $this->filterTypes[$hk];
                        }
                    }
                    if($this->isExport){
                        $data[$key][$hk] = $row[$hk];
                    } else {
                        $data[$key][$hk] = [
                            'value' => $row[$hk],
                            'other' => [],
                        ];
                    }
                } elseif ($column === null){
                    // 这种直接加入到list中，但是header和columns里面没有
                    if(!$this->isExport){
                        $data[$key][$hk] = $row[$hk];
                    }
                }
            }
        }
        $this->listData['listName'] = $this->getListName();
        $this->listData['list'] = $data;
        if($this->isExport){
            $this->listData['headers'] = $this->headers;
        } else {
            if(empty($this->listData['list'])){
                $this->getShowHeaders();
            }
            $this->listData['columnsShow'] = $this->columnsShow;
            $this->listData['filterTypes'] = $this->filterTypesShow;
        }
        unset($data);
    }

    /**
     * 列表为空时需要调用此方法获取一下显示给前端的表头
     * @throws Exception
     */
    public function getShowHeaders(){
        foreach($this->columns as $hk => $column){
            if(is_string($column)){
                $this->headers[] = Tool::textConvert($column);
                if(isset($this->filterTypes[$hk])){
                    $this->filterTypesShow[$hk] = $this->filterTypes[$hk];
                }
            } elseif(is_array($column)) {
                if(!isset($column['header'])){
                    throw new Exception('column数组中必须存在header');
                }
                if(isset($column['hidden'])&&$column['hidden']) continue;
                if(is_callable($column['header'])){
                    $header = $column['header']([]);
                } else {
                    $header = $column['header'];
                }
                if(isset($column['headerOther'])){
                    if(is_callable($column['headerOther'])){
                        $headerOther = $column['headerOther']([]);
                    } else {
                        $headerOther = $column['headerOther'];
                    }
                } else {
                    $headerOther = [];
                }
                $this->columnsShow[] = [
                    'header' => $header,
                    'index' => $hk,
                    'other' => $headerOther,
                ];
                if(isset($this->filterTypes[$hk])){
                    $this->filterTypesShow[$hk] = $this->filterTypes[$hk];
                }
            } elseif (is_callable($column)) {
                $this->columnsShow[] = [
                    'header' => $column([]),
                    'index' => $hk,
                    'other' => [],
                ];
                if(isset($this->filterTypes[$hk])){
                    $this->filterTypesShow[$hk] = $this->filterTypes[$hk];
                }
            }
        }
    }

    /**
     * 按照权限处理哪些字段显示哪些字段不显示
     * @param null $userId
     * @throws Exception
     */
    protected function permissionColumn($userId = null){
        return ;
        $allRole = AdminRole::getFromCache();
        if($userId === null){
            $roleId = \Yii::$app->user->userInfo['roleId'];

        } else {
            $admin = Admin::findOneAsArray('ID=:ID', [':ID'=>$userId]);
            if(!$admin){
                throw new Exception('管理员不存在');
            }
            $roleId = $admin['ROLE_ID'];
            if(!$roleId){
                throw new Exception('管理组不存在');
            }
        }
        // 如果是超级管理员直接返回不做处理
        if($roleId == \Yii::$app->params['superAdminRoleId']){
            return ;
        }
        $role = isset($allRole[$roleId]) ? $allRole[$roleId] : null;
        if($role){
            $className = get_class($this);
            $listModuleArr = explode('\\', $className);
            $listModuleArrCount = count($listModuleArr);
            $listModule = $listModuleArr[$listModuleArrCount-2].'/'.$listModuleArr[$listModuleArrCount-1];
            // 把列里面没有的内容过滤掉
            if($this->columns){
                foreach($this->columns as $key=>$column){
                    if($column !== null){
                        if(!in_array($key, $role['COLUMN_PERMISSION'][$listModule])){
                            unset($this->columns[$key]);
                            // 把筛选里面没有的内容也过滤掉
                            if(isset($this->filterTypes[$key])) unset($this->filterTypes[$key]);
                        }
                    }
                }
            }
        } else {
            $this->columns = [];
        }
    }
}