package com.yeejoin.amos.boot.module.cylinder.biz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.DepartmentBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.bo.RoleBo;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.cylinder.api.service.TzsAuthService;
import com.yeejoin.amos.component.feign.config.TokenOperation;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import com.yeejoin.amos.feign.privilege.model.DepartmentModel;
import com.yeejoin.amos.feign.privilege.model.IdPasswordAuthModel;
import com.yeejoin.amos.feign.privilege.model.RoleModel;
import com.yeejoin.amos.feign.privilege.util.DesUtil;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.RegionModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 特种设备权限服务实现类
 */
@Service
public class TzsAuthServiceImpl implements TzsAuthService {

    @Autowired
    RedisUtils redisUtils;

    @Value("${cti.user.name}")
    private String ctiUserName;

    @Value("${cti.user.pwd}")
    private String ctiUserPwd;


    /**
     * saveUserRedis设置过期时间
     */
    @Value("${redis.cache.failure.time}")
    private Long redisRegionTimeSecond;
    
    @Autowired
    private StartPlatformTokenService startPlatformTokenService;


    @Override
    public List<String> getUserRegionCode() {
        List<String> regionList = new ArrayList<>();
        AgencyUserModel me = Privilege.agencyUserClient.getme().getResult();
        CompanyModel userCompany = me.getCompanys().get(0);
        String regions = userCompany.getRegionSeq();
        if(regions != null) {
            String[] regionsId = regions.split(",");
            for(String regionId:regionsId) {
                RegionModel region = Systemctl.regionClient.getRegion(Long.valueOf(regionId)).getResult();
                regionList.add(region.getRegionCode() + "");
            }
        }
        return regionList;
    }

    @Override
    public List<RegionModel> getUserReginTree() {
        List<String> regionList = this.getUserRegionCode();
        //AgencyUserModel me = Privilege.agencyUserClient.getme().getResult();
        startPlatformTokenService.getToken();
        List<RegionModel> tree = (List<RegionModel>) Systemctl.regionClient.queryForTree(null).getResult();
        // 循环list 将List 封装为 省市区 SET
        Set<String> city = new HashSet<>();
        Set<String> district = new HashSet<>();
        for(String regionCode : regionList) {
            // 判断是否是某个县
            String districtCode = regionCode.substring(4,6);
            if("00".equals(districtCode)) { // 为市
                city.add(regionCode);
            } else { // 为区
                district.add(regionCode);
            }
        }
        // 判断市区是否存在区域码的市，如果存在则移除区
        Iterator<String> disIt = district.iterator();
        while(disIt.hasNext()) {
            String regionCode = disIt.next();
            String tempCity = regionCode.substring(0,4) + "00";
            if(city.contains(tempCity)) {
                disIt.remove();
            }
        }
        // 将tree 转换为K-V形式便于处理
        Map<Integer, RegionModel> tempMap = new HashMap<Integer, RegionModel>();
        RegionModel start = tree.get(0); // 省
        setMap(tempMap,start);
        List<RegionModel> newTree = new ArrayList<RegionModel>();
        List<RegionModel> newCity = new ArrayList<RegionModel>();
        // 如果管理市 取得整个市的数据 如果管理某个县 取得某市某县数据
        Map<String, RegionModel> tempCityMap = new HashMap<String, RegionModel>();
        for(String regionCode : district) {
            // 先拿市 再封装新的城市
            String cityCode = regionCode.substring(0,4) + "00";
            RegionModel tempCity = tempCityMap.get(cityCode);
            if(tempCity == null) {
                List<RegionModel> tempDisList = new ArrayList<RegionModel>();
                tempDisList.add(tempMap.get(Integer.parseInt(regionCode)));
                tempCity = tempMap.get(Integer.parseInt(cityCode));
                tempCity.setChildren(tempDisList);
                tempCityMap.put(cityCode,tempCity);
            } else {
                List<RegionModel> tempDisList = (List<RegionModel>) tempCity.getChildren();
                tempDisList.add(tempMap.get(Integer.parseInt(regionCode)));
            }
        }
        for(String regionCode : city) {// 获取城市
            newCity.add(tempMap.get(Integer.parseInt(regionCode)));
        }
        // 拼接城市
        for(Map.Entry<String, RegionModel> entries : tempCityMap.entrySet()) {
            newCity.add(entries.getValue());
        }
        //start.setChildren(newCity);
        newTree.addAll(newCity);
        return newTree;
    }

    @Override
    public List<RegionModel> getThreeUserReginTree() {
        List<String> regionList = this.getUserRegionCode();
        //AgencyUserModel me = Privilege.agencyUserClient.getme().getResult();
        startPlatformTokenService.getToken();
        List<RegionModel> tree = (List<RegionModel>) Systemctl.regionClient.queryForTree(null).getResult();
        // 循环list 将List 封装为 省市区 SET
        Set<String> city = new HashSet<>();
        Set<String> district = new HashSet<>();
        for(String regionCode : regionList) {
            // 判断是否是某个县
            String districtCode = regionCode.substring(4,6);
            if("00".equals(districtCode)) { // 为市
                city.add(regionCode);
            } else { // 为区
                district.add(regionCode);
            }
        }
        // 判断市区是否存在区域码的市，如果存在则移除区
        Iterator<String> disIt = district.iterator();
        while(disIt.hasNext()) {
            String regionCode = disIt.next();
            String tempCity = regionCode.substring(0,4) + "00";
            if(city.contains(tempCity)) {
                disIt.remove();
            }
        }
        // 将tree 转换为K-V形式便于处理
        Map<Integer, RegionModel> tempMap = new HashMap<Integer, RegionModel>();
        RegionModel start = tree.get(0); // 省
        filterAndMapRegions(tempMap,start);
        List<RegionModel> newTree = new ArrayList<RegionModel>();
        List<RegionModel> newCity = new ArrayList<RegionModel>();
        // 如果管理市 取得整个市的数据 如果管理某个县 取得某市某县数据
        Map<String, RegionModel> tempCityMap = new HashMap<String, RegionModel>();
        for(String regionCode : district) {
            // 先拿市 再封装新的城市
            String cityCode = regionCode.substring(0,4) + "00";
            RegionModel tempCity = tempCityMap.get(cityCode);
            if(tempCity == null) {
                List<RegionModel> tempDisList = new ArrayList<RegionModel>();
                tempDisList.add(tempMap.get(Integer.parseInt(regionCode)));
                tempCity = tempMap.get(Integer.parseInt(cityCode));
                tempCity.setChildren(tempDisList);
                tempCityMap.put(cityCode,tempCity);
            } else {
                List<RegionModel> tempDisList = (List<RegionModel>) tempCity.getChildren();
                tempDisList.add(tempMap.get(Integer.parseInt(regionCode)));
            }
        }
        for(String regionCode : city) {// 获取城市
            newCity.add(tempMap.get(Integer.parseInt(regionCode)));
        }
        // 拼接城市
        for(Map.Entry<String, RegionModel> entries : tempCityMap.entrySet()) {
            newCity.add(entries.getValue());
        }
        //start.setChildren(newCity);
        newTree.addAll(newCity);
        return newTree;
    }


    private void setMap(Map<Integer, RegionModel> tempMap, RegionModel start) {
        tempMap.put(start.getRegionCode(),start);
        if(start.getChildren() != null) {
            List<RegionModel> children = (List<RegionModel>) start.getChildren();
            for (RegionModel temp : children) {
                setMap(tempMap,temp);
            }
        }
    }

    private static void filterAndMapRegions(Map<Integer, RegionModel> tempMap, RegionModel start) {
        // 先检查并过滤子节点
        if (start.getChildren() != null) {
            Iterator<RegionModel> iterator = start.getChildren().iterator();
            while (iterator.hasNext()) {
                RegionModel child = iterator.next();
                if ("4".equals(child.getLevel().trim())) {
                    iterator.remove();
                } else {
                    filterAndMapRegions(tempMap, child);
                }
            }
        }
        if (!"4".equals(start.getLevel().trim())) {
            tempMap.put(start.getRegionCode(), start);
        }
    }

    private void loginCtiUser() {
        String passwd = DesUtil.encode(ctiUserPwd, "qaz");
        IdPasswordAuthModel loninData = new IdPasswordAuthModel();
        loninData.setLoginId(ctiUserName);
        loninData.setPassword(passwd);
        FeignClientResult loginResult = Privilege.authClient.idpassword(loninData);
        if(loginResult.getStatus() == 200) {
            HashMap resultMap = (HashMap) loginResult.getResult();
            redisUtils.set(RedisKey.CTI_USER_TOKEN,  resultMap.get("token").toString(), redisRegionTimeSecond);
        }
    }


    public void setRequestContext() {
        // 需要登录后台账号
        RequestContext.setAppKey("AMOS_STUDIO");
        RequestContext.setProduct("AMOS_STUDIO_WEB");
        synchronized (TzsAuthServiceImpl.class) {
            if (redisUtils.hasKey(RedisKey.CTI_USER_TOKEN)) {
                // 验证token
                boolean validToken = TokenOperation.refresh(redisUtils.get(RedisKey.CTI_USER_TOKEN).toString());
                // 登陆
                if (!validToken) {
                    this.loginCtiUser();
                }
            } else { // 登陆
                this.loginCtiUser();
            }
        }
        String ctiToken = redisUtils.get(RedisKey.CTI_USER_TOKEN).toString();
        RequestContext.setToken(ctiToken);
        try {
            FeignClientResult<AgencyUserModel> agencyUserModel = Privilege.agencyUserClient.queryByUserName(ctiUserName);
            AgencyUserModel userModel = agencyUserModel.getResult();
            RequestContext.setExeUserId(userModel.getUserId());
            saveUserRedis(userModel, ctiToken);
        } catch (Exception e) {
            //删除失效token缓存
            throw new RuntimeException(e.getMessage());
        }

    }


    private void saveUserRedis(AgencyUserModel user, String token) {
        String authToken = RedisKey.buildReginKey(user.getUserId(), token);
        if (redisUtils.hasKey(authToken)) {
            return;
        }
        CompanyBo company = new CompanyBo();
        DepartmentBo department = new DepartmentBo();
        RoleBo role = new RoleBo();
        CompanyModel companyM = user.getCompanys() != null ? user.getCompanys().get(0) : null ;
        Bean.copyExistPropertis(companyM, company);
        Map<Long, List<DepartmentModel>> mapDepartments = user.getCompanyDepartments();
        DepartmentModel departmentM = companyM != null ? mapDepartments.get(companyM.getSequenceNbr()).get(0) : null ;
        Bean.copyExistPropertis(departmentM, department);
        Map<Long, List<RoleModel>> roles = user.getOrgRoles();
        Long sequenceNbr;
        if (departmentM == null) {
            sequenceNbr = null;
        } else {
            sequenceNbr = departmentM.getSequenceNbr();
        }
        RoleModel roleM = null;
        if (sequenceNbr == null) {
            roleM = companyM != null ?roles.get(companyM.getSequenceNbr()).get(0) : null;
        } else {
            roleM = roles.get(sequenceNbr).get(0);
        }
        Bean.copyExistPropertis(roleM, role);
        ReginParams reginParams = new ReginParams();
        reginParams.setCompany(company);
        reginParams.setRole(role);
        reginParams.setDepartment(department);
        reginParams.setUserModel(user);
        redisUtils.set(authToken, JSONObject.toJSONString(reginParams), redisRegionTimeSecond);
    }


}