/**
 * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.common.service;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.jeeplus.common.persistence.BaseEntity;
import com.jeeplus.common.utils.JedisUtils;
import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.modules.sys.dao.OfficeDao;
import com.jeeplus.modules.sys.entity.Office;
import com.jeeplus.modules.sys.entity.Role;
import com.jeeplus.modules.sys.entity.User;
import com.jeeplus.modules.sys.service.OfficeService;
import com.jeeplus.modules.sys.utils.UserUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Service基类
 *
 * @author jeeplus
 * @version 2014-05-16
 */
@Transactional(readOnly = true)
public abstract class BaseService {

    public static final String BRANCH_OFFICE_PREFIX = "BRANCH_OFFICE_";
    public static final String CHILD_OFFICE_PREFIX = "CHILD_OFFICE_";

    /**
     * 日志对象
     */
    protected Logger logger = LoggerFactory.getLogger(getClass());


    /**
     * 数据范围过滤
     *
     * @param user        当前用户对象，通过“entity.getCurrentUser()”获取
     * @param officeAlias 机构表别名，多个用“,”逗号隔开。
     * @param userAlias   用户表别名，多个用“,”逗号隔开，传递空，忽略此参数
     * @return 标准连接条件对象
     */
    public static String dataScopeFilter(User user, String officeAlias, String userAlias, String sAlias, String menuId) {
        return genSqlString("menu1_",user, menuId,sAlias, "and");
    }

    public static String genSqlString(String prefix, User user, String menuId,String sAlias, String logic) {
        if (user.isAdmin()) {
            return "";
        }
        Jedis jedis = null;
        try {
            jedis = JedisUtils.getResource();
            StringBuilder sqlString = new StringBuilder();
            String sql = jedis.hget( prefix+ user.getCompany().getId() + "_" + user.getId(), menuId);
            if (StringUtils.isNotBlank(sql)) {
                //return sql;
            }
            // 进行权限过滤，多个岗位权限范围之间为或者关系。
            List<Role> fnlRoleList = new ArrayList<>();
            List<Role> selfRoleList = new ArrayList<>();
            List<Role> roleList = UserUtils.getRolesByMenu(user, menuId);
            if (roleList != null && roleList.size() > 0) {
                for (Role role : roleList) {
                    if (Role.DATA_SCOPE_COMPANY_AND_CHILD.equals(role.getDataScope())) {
                        fnlRoleList.clear();
                        fnlRoleList.add(role);
                        break;
                    } else if (!Role.DATA_SCOPE_SELF.equals(role.getDataScope())) {
                        fnlRoleList.add(role);
                    } else {
                        selfRoleList.add(role);
                    }
                }
            }
            Set<String> officeSet = new HashSet<>();
            for (Role r : fnlRoleList) {
                if (Role.DATA_SCOPE_COMPANY_AND_CHILD.equals(r.getDataScope())) {
                    if(StringUtils.isBlank(sAlias)){
                        return logic + "1=1";
                    }
                    sqlString.append(logic + " a.company_id = '" + r.getCompany().getId() + "'");
                    return sqlString.toString();
                }
                if (Role.DATA_SCOPE_COMPANY.equals(r.getDataScope())) {
                    //查询分公司的所有部门
                    String key = BRANCH_OFFICE_PREFIX + r.getBranchCompany().getId();
                    String s = jedis.get(key);
                    List<String> officeIds = null;
                    if (StringUtils.isBlank(s)) {
                        officeIds = UserUtils.findBranchOfficeId(r.getBranchCompany());
                    } else {
                        officeIds = JSON.parseArray(s, String.class);
                    }
                    if (officeIds != null && officeIds.size() > 0) {
                        jedis.set(key, JSON.toJSONString(officeIds));
                        jedis.expire(key, 60 * 60 * 8);
                        officeSet.addAll(officeIds);
                    }
                    continue;
                }
                if (Role.DATA_SCOPE_OFFICE_AND_CHILD.equals(r.getDataScope())) {
                    //查询当前部门的所有子部门
                    String key = CHILD_OFFICE_PREFIX + r.getOffice().getId();
                    String s = jedis.get(key);
                    List<String> officeIds = new ArrayList<>();
                    if (StringUtils.isBlank(s)) {
                        officeIds = UserUtils.findChildOfficeId(r.getOffice());
                    } else {
                        officeIds = JSON.parseArray(s, String.class);
                    }
                    officeIds.add(r.getOffice().getId());
                    jedis.set(key, JSON.toJSONString(officeIds));
                    jedis.expire(key, 60 * 60 * 8);
                    officeSet.addAll(officeIds);
                    continue;
                }
                if (Role.DATA_SCOPE_OFFICE.equals(r.getDataScope())) {
                    officeSet.add(r.getOffice().getId());
                    continue;
                }
            }
            //所有部门权限
            if (officeSet != null) {
                if (officeSet.size() > 1) {
                    sqlString.append("a.office_id in (");
                    for (String s : officeSet) {
                        sqlString.append("'" + s + "',");
                    }
                    sqlString.deleteCharAt(sqlString.length() - 1);
                    sqlString.append(")");
                } else if (officeSet.size() == 1) {
                    for (String s : officeSet) {
                        sqlString.append("a.office_id ='" + s + "'");
                    }
                }
            }
            //所有个人权限
            for (int i = 0; i < selfRoleList.size(); i++) {
                Role role = selfRoleList.get(i);
                if (officeSet.contains(role.getOffice().getId())) {
                    continue;
                }
                if (i > 0 || sqlString.length() > 0) {
                    sqlString.append("or ");
                }
                sqlString.append("(a.office_id='" + role.getOffice().getId() + "' and a.create_by='" + user.getId() + "')");
            }

            if (StringUtils.isNotBlank(sqlString.toString())) {
                sql = logic+" (" + sqlString.toString() + ")";
                jedis.hset(prefix + user.getCompany().getId() + "_" + user.getId(), menuId, sql);
            }
            return sql;
        } catch (Exception e) {
            return "and a.company_id='" + user.getCompany().getId() + "' and a.create_by='" + user.getId() + "'";
        } finally {
            JedisUtils.returnResource(jedis);
        }
    }

    /**
     * 数据范围过滤
     *
     * @param user        当前用户对象，通过“entity.getCurrentUser()”获取
     * @param officeAlias 机构表别名，多个用“,”逗号隔开。
     * @param userAlias   用户表别名，多个用“,”逗号隔开，传递空，忽略此参数
     * @return 标准连接条件对象
     */
    public static String dataScopeFilterOR(User user, String officeAlias, String userAlias, String sAlias, String menuId) {
        return genSqlString("menu2_",user, menuId, sAlias,"or");
    }


    /**
     * 数据范围过滤 只显示当前企业下数据
     *
     * @param user        当前用户对象，通过“entity.getCurrentUser()”获取
     * @param officeAlias 机构表别名，多个用“,”逗号隔开。
     * @param userAlias   用户表别名，多个用“,”逗号隔开，传递空，忽略此参数
     * @return 标准连接条件对象
     */
    public static String dataScopeFilter2(User user, String officeAlias, String userAlias) {

        StringBuilder sqlString = new StringBuilder();

        // 进行权限过滤，多个岗位权限范围之间为或者关系。
        List<String> dataScope = Lists.newArrayList();

        // 超级管理员，跳过权限过滤
        if (!user.isAdmin()) {
            boolean isDataScopeAll = false;
            Role r = UserUtils.getSelectRole().get(0);
            //for (Role r : user.getRoleList()){
            user.setCompany(UserUtils.getSelectCompany());
            user.setOffice(UserUtils.getSelectOffice());
            for (String oa : StringUtils.split(officeAlias, ",")) {
                if (!dataScope.contains(r.getDataScope()) && StringUtils.isNotBlank(oa)) {
                    if (Role.DATA_SCOPE_ALL.equals(r.getDataScope())) {
                        isDataScopeAll = true;
                    } else if (Role.DATA_SCOPE_COMPANY_AND_CHILD.equals(r.getDataScope())) {
                        sqlString.append(" OR " + oa + ".id = '" + user.getCompany().getId() + "'");
                        sqlString.append(" OR find_in_set( '" + user.getCompany().getId() + "'," + oa + ".parent_ids)");
                    } else if (Role.DATA_SCOPE_COMPANY.equals(r.getDataScope())) {
                        sqlString.append(" OR " + oa + ".id = '" + user.getCompany().getId() + "'");
                        // 包括本公司下的部门 （type=1:公司；type=2：部门）
                        sqlString.append(" OR (" + oa + ".parent_id = '" + user.getCompany().getId() + "' AND " + oa + ".type = '2')");
                    } else if (Role.DATA_SCOPE_OFFICE_AND_CHILD.equals(r.getDataScope())) {
                        sqlString.append(" OR " + oa + ".id = '" + user.getOffice().getId() + "'");
                        sqlString.append(" OR find_in_set( '" + user.getOffice().getId() + "'," + oa + ".parent_ids)");
                    } else if (Role.DATA_SCOPE_OFFICE.equals(r.getDataScope())) {
                        //查看分公司数据
                        sqlString.append(" OR " + oa + ".id = '" + user.getBranchOffice().getId() + "'");
                        sqlString.append(" OR find_in_set( '" + user.getBranchOffice().getId() + "'," + oa + ".parent_ids)");

                        /*sqlString.append(" OR " + oa + ".id = '" + user.getOffice().getId() + "'");*/
                    } else if (Role.DATA_SCOPE_CUSTOM.equals(r.getDataScope())) {
//							String officeIds =  StringUtils.join(r.getOfficeIdList(), "','");
//							if (StringUtils.isNotEmpty(officeIds)){
//								sqlString.append(" OR " + oa + ".id IN ('" + officeIds + "')");
//							}
                        sqlString.append(" OR EXISTS (SELECT 1 FROM sys_role_office WHERE role_id = '" + r.getId() + "'");
                        sqlString.append(" AND office_id = " + oa + ".id)");
                    }
                    //else if (Role.DATA_SCOPE_SELF.equals(r.getDataScope())){
                    dataScope.add(r.getDataScope());
                }
            }
            //}
            // 如果没有全部数据权限，并设置了用户别名，则当前权限为本人；如果未设置别名，当前无权限为已植入权限
            if (!isDataScopeAll) {
                if (StringUtils.isNotBlank(userAlias)) {
                    for (String ua : StringUtils.split(userAlias, ",")) {
                        sqlString.append(" OR " + ua + ".id = '" + user.getId() + "'");
                    }
                } else {
                    for (String oa : StringUtils.split(officeAlias, ",")) {
                        //sqlString.append(" OR " + oa + ".id  = " + user.getOffice().getId());
                        sqlString.append(" OR " + oa + ".id IS NULL");
                    }
                }
            } else {
                // 如果包含全部权限，则去掉之前添加的所有条件，并跳出循环。
                sqlString = new StringBuilder();
            }
        }
        if (StringUtils.isNotBlank(sqlString.toString())) {
            return " AND (" + sqlString.substring(4) + ")";
        }
        return "";
    }


    /**
     * 数据范围过滤（符合业务表字段不同的时候使用，采用exists方法）
     *
     * @param entity       当前过滤的实体类
     * @param sqlMapKey    sqlMap的键值，例如设置“dsf”时，调用方法：${sqlMap.sdf}
     * @param officeWheres office表条件，组成：部门表字段=业务表的部门字段
     * @param userWheres   user表条件，组成：用户表字段=业务表的用户字段
     * @example dataScopeFilter(user, " dsf ", " id = a.office_id ", " id = a.create_by ");
     * dataScopeFilter(entity, "dsf", "code=a.jgdm", "no=a.cjr"); // 适应于业务表关联不同字段时使用，如果关联的不是机构id是code。
     */
    public static void dataScopeFilter(BaseEntity<?> entity, String sqlMapKey, String officeWheres, String userWheres) {

        User user = entity.getCurrentUser();

        // 如果是超级管理员，则不过滤数据
        if (user.isAdmin()) {
            return;
        }

        // 数据范围（1：所有数据；2：所在公司及以下数据；3：所在公司数据；4：所在部门及以下数据；5：所在部门数据；8：仅本人数据；9：按明细设置）
        StringBuilder sqlString = new StringBuilder();

        // 获取到最大的数据权限范围
        String roleId = "";
        int dataScopeInteger = 8;
        //for (Role r : user.getRoleList()){
        Role r = UserUtils.getSelectRole().get(0);
        //for (Role r : user.getRoleList()){
        user.setCompany(UserUtils.getSelectCompany());
        user.setOffice(UserUtils.getSelectOffice());
        int ds = Integer.valueOf(r.getDataScope());
        if (ds == 9) {
            roleId = r.getId();
            dataScopeInteger = ds;
            //break;
        } else if (ds < dataScopeInteger) {
            roleId = r.getId();
            dataScopeInteger = ds;
        }
        //}
        String dataScopeString = String.valueOf(dataScopeInteger);

        // 生成部门权限SQL语句
        for (String where : StringUtils.split(officeWheres, ",")) {
            if (Role.DATA_SCOPE_COMPANY_AND_CHILD.equals(dataScopeString)) {
                // 包括本公司下的部门 （type=1:公司；type=2：部门）
                sqlString.append(" AND EXISTS (SELECT 1 FROM SYS_OFFICE");
                sqlString.append(" WHERE type='2'");
                sqlString.append(" AND (id = '" + user.getCompany().getId() + "'");
                sqlString.append(" OR parent_ids LIKE '" + user.getCompany().getParentIds() + user.getCompany().getId() + ",%')");
                sqlString.append(" AND " + where + ")");
            } else if (Role.DATA_SCOPE_COMPANY.equals(dataScopeString)) {
                sqlString.append(" AND EXISTS (SELECT 1 FROM SYS_OFFICE");
                sqlString.append(" WHERE type='2'");
                sqlString.append(" AND id = '" + user.getCompany().getId() + "'");
                sqlString.append(" AND " + where + ")");
            } else if (Role.DATA_SCOPE_OFFICE_AND_CHILD.equals(dataScopeString)) {
                sqlString.append(" AND EXISTS (SELECT 1 FROM SYS_OFFICE");
                sqlString.append(" WHERE (id = '" + user.getOffice().getId() + "'");
                sqlString.append(" OR parent_ids LIKE '" + user.getOffice().getParentIds() + user.getOffice().getId() + ",%')");
                sqlString.append(" AND " + where + ")");
            } else if (Role.DATA_SCOPE_OFFICE.equals(dataScopeString)) {
                sqlString.append(" AND EXISTS (SELECT 1 FROM SYS_OFFICE");
                sqlString.append(" WHERE id = '" + user.getOffice().getId() + "'");
                sqlString.append(" AND " + where + ")");
            } else if (Role.DATA_SCOPE_CUSTOM.equals(dataScopeString)) {
                sqlString.append(" AND EXISTS (SELECT 1 FROM sys_role_office ro123456, sys_office o123456");
                sqlString.append(" WHERE ro123456.office_id = o123456.id");
                sqlString.append(" AND ro123456.role_id = '" + roleId + "'");
                sqlString.append(" AND o123456." + where + ")");
            }
        }
        // 生成个人权限SQL语句
        for (String where : StringUtils.split(userWheres, ",")) {
            if (Role.DATA_SCOPE_SELF.equals(dataScopeString)) {
                sqlString.append(" AND EXISTS (SELECT 1 FROM sys_user");
                sqlString.append(" WHERE id='" + user.getId() + "'");
                sqlString.append(" AND " + where + ")");
            }
        }

//		System.out.println("dataScopeFilter: " + sqlString.toString());

        // 设置到自定义SQL对象
        entity.getSqlMap().put(sqlMapKey, sqlString.toString());

    }

    /**
     * @param user
     * @param sAlias 分公司表别名
     * @return
     */
    public static String dataScopeBranchOfficeFilter(User user, String sAlias) {
        if (user.isAdmin()) {
            return "";
        }
        if (StringUtils.isBlank(sAlias)) {
            return "";
        }
        List<Role> selectRoles = UserUtils.getSelectRole();
        if (selectRoles == null || selectRoles.isEmpty()) {
            return "";
        }

        Set<String> branchIds = new HashSet<>();
        for (Role role : selectRoles) {
            branchIds.add(role.getBranchCompany() == null ? null : role.getBranchCompany().getId());
        }

        StringBuilder sql = new StringBuilder("and " + sAlias + ".id in (");
        for (String branchId : branchIds) {
            if (StringUtils.isBlank(branchId)) {
                sql.append("'" + user.getComId() + "',");
            } else {
                sql.append("'" + branchId + "',");
            }
        }
        sql.deleteCharAt(sql.length() - 1);
        sql.append(")");
        return sql.toString();
    }


    public static String dataScopeFilterOR(User user, String officeAlias,String menuId) {
        Jedis jedis = null;
        try {
            jedis = JedisUtils.getResource();
            StringBuilder sqlString = new StringBuilder();
            String sql = jedis.hget("menu2_"+user.getCompany().getId()+"_"+user.getId(), menuId);
            if (StringUtils.isNotBlank(sql)) {
                return sql;
            } else {
                List<Role> roleList = UserUtils.getRolesByMenu(user, menuId);
                // 超级管理员，跳过权限过滤
                if (!user.isAdmin()) {
                    boolean isDataScopeAll = false;
                    if (UserUtils.getSelectRole() != null && UserUtils.getSelectRole().size() > 0) {
                        for (Role role : UserUtils.getSelectRole()) {
                            if (Role.DATA_SCOPE_COMPANY_AND_CHILD.equals(role.getDataScope())) {
                                roleList.clear();
                                roleList.add(role);
                                break;
                            } else if (!Role.DATA_SCOPE_SELF.equals(role.getDataScope()) || UserUtils.getSelectRole().size() == 1) {
                                roleList.add(role);
                            }
                        }
                    }
                    for (Role r : roleList) {
                        int count = 0;
                        sqlString.append(" ( (");
                        for (String oa : StringUtils.split(officeAlias, ",")) {
                            if (StringUtils.isNotBlank(oa)) {
                                if (Role.DATA_SCOPE_ALL.equals(r.getDataScope())) {
                                    isDataScopeAll = true;
                                } else if (Role.DATA_SCOPE_COMPANY_AND_CHILD.equals(r.getDataScope())) {
                                    sqlString.append(oa + ".id = '" + user.getCompany().getId() + "'");
                                    sqlString.append(" OR " + oa + ".parent_ids LIKE '" + user.getCompany().getParentIds() + user.getCompany().getId() + ",%'");
                                } else if (Role.DATA_SCOPE_COMPANY.equals(r.getDataScope())) {
                                    if (user.getBranchOffice() != null && StringUtils.isNotBlank(user.getBranchOffice().getId())) {
                                        sqlString.append(oa + ".branch_office = '" + user.getBranchOffice().getId() + "'");
                                    } else {
                                        sqlString.append(oa + ".branch_office is null ");
                                    }
                                    sqlString.append("and (" + oa + ".id = '" + user.getCompany().getId() + "'");
                                    sqlString.append(" OR " + oa + ".parent_ids LIKE '" + user.getCompany().getParentIds() + user.getCompany().getId() + ",%')");
								/*sqlString.append(oa + ".id = '" + user.getCompany().getId() + "'");
								// 包括本公司下的部门 （type=1:公司；type=2：部门）
								sqlString.append(" OR (" + oa + ".parent_id = '" + user.getCompany().getId() + "' AND " + oa + ".type = '2')");
								*/
                                } else if (Role.DATA_SCOPE_OFFICE_AND_CHILD.equals(r.getDataScope())) {
                                    sqlString.append(oa + ".id = '" + user.getOffice().getId() + "'");
                                    sqlString.append(" OR " + oa + ".parent_ids LIKE '" + user.getOffice().getParentIds() + user.getOffice().getId() + ",%'");
                                } else if (Role.DATA_SCOPE_OFFICE.equals(r.getDataScope())) {
                                    /*sqlString.append(" OR " + oa + ".id = '" + user.getOffice().getId() + "'");*/
                                    //查看分公司数据
                                    sqlString.append(oa + ".id = '" + user.getBranchOffice().getId() + "'");
                                    sqlString.append(" OR " + oa + ".parent_ids LIKE '" + user.getBranchOffice().getParentIds() + user.getBranchOffice().getId() + ",%'");
                                } else {
                                    count = 1;
                                }
                            }
                        }
                        //}
                        // 如果没有全部数据权限，并设置了用户别名，则当前权限为本人；如果未设置别名，当前无权限为已植入权限
                        if (!isDataScopeAll) {
                            if (count == 1) {
                                sqlString.append("a.create_by IS NULL");
                            } else {
                                sqlString.append(" OR " + "a.create_by IS NULL");
                            }
                        } else {
                            // 如果包含全部权限，则去掉之前添加的所有条件，并跳出循环。
                            sqlString = new StringBuilder();
                        }
                        sqlString.append(") ) OR");
                    }
                }
                if (StringUtils.isNotBlank(sqlString.toString())) {
                    if (roleList.size() > 1) {
                        sql = "OR(" + sqlString.substring(0, sqlString.length() - 3) + ")";
                    } else {
                        sql = "OR" + sqlString.substring(0, sqlString.length() - 3);
                    }
                    jedis.hset("menu2_"+user.getCompany().getId()+"_"+user.getId(), menuId, sql);
                    return sql;
                }
            }
        }catch (Exception e){
            System.out.println("------------------dataScopeFilterOR Exception e:"+e);
        }finally {
            JedisUtils.returnResource(jedis);
        }
            //return  "OR (s.id = '"+user.getCompany().getId()+"' AND a.create_by = '" + user.getId()+"')";
        return "OR 1=1";
    }
}
