package fcb.project.manager.base.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import fcb.project.manager.base.config.FcbConfig;
import fcb.project.manager.base.dao.TmEstateDao;
import fcb.project.manager.base.dto.scene.SceneProEntity;
import fcb.project.manager.base.entity.ContextTokenBean;
import fcb.project.manager.base.entity.SceneRspBean;
import fcb.project.manager.base.entity.TmEstate;
import fcb.project.manager.base.entity.TmHouse;
import fcb.project.manager.base.enums.DeleteStatus;
import fcb.project.manager.base.enums.HouseStatus;
import fcb.project.manager.base.enums.SysUserRoleEnums;
import fcb.project.manager.base.param.house.QueryHouseParam;
import fcb.project.manager.base.service.ITmEstateService;
import fcb.project.manager.base.service.custom.PanoService;
import fcb.project.manager.base.utils.DateUtil;
import fcb.project.manager.base.utils.ExcelUtil;
import fcb.project.manager.base.vo.house.HouseVO;
import fcb.project.manager.core.feignInterfaces.SceneFeign;
import fdage.back.sdk.base.enums.ResultCodeEnum;
import fdage.back.sdk.base.exception.CommonBaseException;
import fdage.back.sdk.base.uuid.SnowFlakeUUidUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author abner
 * @since 2021-01-07
 */
@Service
@Log4j2
@RequiredArgsConstructor
public class TmEstateServiceImpl extends ServiceImpl<TmEstateDao, TmEstate> implements ITmEstateService {

    private final PanoService panoService;
    private final FcbConfig fcbConfig;
    private final TmAuditServiceImpl tmAuditService;
    private final SceneFeign sceneFeign;
    private final TmOperationServiceImpl tmOperationService;
    private TmHouseServiceImpl tmHouseService;

    @Autowired
    public void setTmHouseService(TmHouseServiceImpl tmHouseService) {
        this.tmHouseService = tmHouseService;
    }

    public IPage<HouseVO> listProject(QueryHouseParam queryHouseParam, ContextTokenBean contextUserInfo, String token) {
        produceQuery(queryHouseParam, contextUserInfo);

        Page page = new Page().setCurrent(queryHouseParam.getPageNum()).setSize(queryHouseParam.getPageSize());
        IPage<HouseVO> vos = getBaseMapper().listProject(page, queryHouseParam);
        log.info("输出结果-{}", new Gson().toJson(vos.getRecords()));

        produceRes(vos.getRecords(), token);
        return vos;
    }

    public String exportProjectList(QueryHouseParam queryHouseParam, ContextTokenBean contextUserInfo, String token) {
        produceQuery(queryHouseParam, contextUserInfo);
        List<HouseVO> houseList = getBaseMapper().exportProject(queryHouseParam);
        produceRes(houseList, token);

        //导出的数据
        Map<String, String> item;
        List<Map> dataList = new ArrayList<>();
        int num = 0;
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        List<String> cols = Arrays.asList("序号", "楼盘编码", "楼盘名称", "航拍数量", "景观图数量", "售楼处数量", "样板间数量", "讲房售楼处数量", "讲房样板间数量", "讲房点位数量",
                "创建时间", "更新时间", "状态", "审核人", "审核时间");
        ExcelUtil excelUtil = new ExcelUtil(cols);
        for(HouseVO house : houseList){
            int index = 0;
            num += 1;
            //楼盘数据
            item = new HashMap(20);
            item.put(excelUtil.getColeNames().get(index++), String.valueOf(num));
            item.put(excelUtil.getColeNames().get(index++), house.getFcbEstateId());
            item.put(excelUtil.getColeNames().get(index++), house.getEstateName());
            item.put(excelUtil.getColeNames().get(index++), house.getBuilding() != null ? house.getBuilding().toString() : "0");
            item.put(excelUtil.getColeNames().get(index++), house.getGarden() != null ? house.getGarden().toString() : "0");
            item.put(excelUtil.getColeNames().get(index++), house.getSales() != null ? house.getSales().toString() : "0");
            item.put(excelUtil.getColeNames().get(index++), house.getHouse() != null ? house.getHouse().toString() : "0");
            item.put(excelUtil.getColeNames().get(index++), house.getSaleVideos().toString());
            item.put(excelUtil.getColeNames().get(index++), house.getHouseVideos().toString());
            item.put(excelUtil.getColeNames().get(index++), house.getPoints() != null ? house.getPoints().toString() : "0");
            item.put(excelUtil.getColeNames().get(index++), house.getCreateTime().format(df));
            item.put(excelUtil.getColeNames().get(index++), house.getUpdateTime().format(df));
            item.put(excelUtil.getColeNames().get(index++), HouseStatus.get(house.getStatus()).getDesc());
            item.put(excelUtil.getColeNames().get(index++), house.getAuditorName());
            item.put(excelUtil.getColeNames().get(index++), house.getAuditTime().format(df));
            dataList.add(item);
        }

        String date = DateUtil.date2String(new Date(), DateUtil.YYYYMMDDHHMMSS_DATA_FORMAT);

        if (queryHouseParam.getStatus() == null) {
            queryHouseParam.setStatus(HouseStatus.ALL.getCode());
        }
        String dateStr = "VR看房楼盘项目-"  + "-" + date;
        String fileName = dateStr + ".xls";
        File file = new File(fcbConfig.getExcelLocalPath() + fileName);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }

        excelUtil.writeExcel(dataList, excelUtil.getColeNames().size(), fcbConfig.getExcelLocalPath() + fileName, dateStr);
        return fcbConfig.getOuterSceneVrHost() + "excel/" + dateStr + ".xls";
    }


    private void produceQuery(QueryHouseParam queryHouseParam, ContextTokenBean contextUserInfo) {
        if (!StringUtils.equals(contextUserInfo.getRoleKey(), SysUserRoleEnums.ADMIN.getRoleKey())
                && !StringUtils.equals(contextUserInfo.getRoleKey(), SysUserRoleEnums.GROUP.getRoleKey())) {
            queryHouseParam.setDepartmentId(contextUserInfo.getDepartmentId());
        }
        if (queryHouseParam.getStatus() != null && HouseStatus.REJECT.getCode().equals(queryHouseParam.getStatus())) {
            queryHouseParam.setStatues(Arrays.asList(HouseStatus.REJECT.getCode(), HouseStatus.REGION_REJECT.getCode()));
        }
    }



    // todo
    private void produceRes(List<HouseVO> houseVOS, String token) {
        if(null != houseVOS && houseVOS.size() > 0){
            List<String> getAllHouseIds = new ArrayList<>();
            for (int i = 0; i < houseVOS.size(); i++) {
                getAllHouseIds.add(houseVOS.get(i).getHouseId());
            }
            //从720获取最新的预览路径，重新封装给前端展示
            TreeMap<String , Object> treeMap =  panoService.getHouseVrlinks(getAllHouseIds , token);

            //从720获取统计数据
            Map<String, Object> statistics;
            Map<String, Object> panoSceneWithTypesMap;

            //当前房源所有场景码集合
            List<String> allSceneNums;

            //四维看看接口参数
            Map<String, String> param = new HashMap<>();
            //四维看看获取统计结果
            SceneRspBean sceneRspBean;

            for (int i = 0; i < houseVOS.size(); i++) {
                String vrId = houseVOS.get(i).getHouseId();
                //获取当前房源的审核记录数，用于前端判决是否展示审核历史图标
                houseVOS.get(i).setCountNum(tmAuditService.countAuditNum(vrId));
                if(!CollectionUtils.isEmpty(treeMap)){
                    String path = (String) treeMap.get(vrId);
                    if(StringUtils.isNotBlank(path)){
                        String outerHost = fcbConfig.getOuterSceneVrHost().substring(0 , fcbConfig.getOuterSceneVrHost().length() - 1);
                        String innerHost = fcbConfig.getInnerSceneVrHost().substring(0 , fcbConfig.getInnerSceneVrHost().length() - 1);
                        houseVOS.get(i).setInnerVrLink(innerHost + path);
                        houseVOS.get(i).setVrLink(outerHost + path);
                    }
                }
                //调用720云接口，获取统计数据map
                statistics = panoService.getStatistics(vrId, token);
                if(statistics != null) {
                    houseVOS.get(i).setGarden(statistics.get("garden"));
                    houseVOS.get(i).setHouse(statistics.get("house"));
                    houseVOS.get(i).setBuilding(statistics.get("building"));
                    houseVOS.get(i).setSales(statistics.get("sales"));
                }

                int salesVideos = 0;
                int houseVideos = 0;
                panoSceneWithTypesMap = panoService.listPanoSceneWithTypes(houseVOS.get(i).getHouseId(), token);

                if (MapUtils.isNotEmpty(panoSceneWithTypesMap)) {
                    List<String> nums = panoSceneWithTypesMap.entrySet().stream().map(e -> e.getValue().toString()).collect(Collectors.toList());

                    sceneRspBean = sceneFeign.listScenesInNums(nums, token);
                    List<SceneProEntity> scenes = (List<SceneProEntity>) sceneRspBean.getData();
                    log.info("远程调用listScenesInNums接口，入参-{}", nums);
                    log.info("远程调用listScenesInNums接口,返回数据-{}", new Gson().toJson(scenes));
                    for (SceneProEntity scene : scenes) {
                        String videoStr = scene.getVideos();
                        JSONObject scenejson = new JSONObject();
                        if(videoStr != null) {
                            scenejson = JSONObject.parseObject(videoStr);
                        }
                        Object data = scenejson.get("data");
                        if (data != null && data instanceof JSONArray) {
                            JSONArray jsonArray = (JSONArray) data;
                            if (jsonArray.size() != 0) {
                                Optional<Map.Entry<String, Object>> existData = panoSceneWithTypesMap.entrySet().stream().filter(m ->
                                        "sales".equals(m.getKey()) && scene.getNum().equals(m.getValue().toString())).findAny();
                                if (existData.isPresent()) {
                                    salesVideos += jsonArray.size();
                                }
                                existData = panoSceneWithTypesMap.entrySet().stream().filter(m ->
                                        "room".equals(m.getKey()) && scene.getNum().equals(m.getValue().toString())).findAny();
                                if (existData.isPresent()) {
                                    houseVideos += jsonArray.size();
                                }

                            }
                        }
                    }
                    houseVOS.get(i).setSaleVideos(salesVideos);
                    houseVOS.get(i).setHouseVideos(houseVideos);
                }

                allSceneNums = panoService.getAllSceneNums(vrId, token);
                if(allSceneNums != null){
                    param.put("sceneNum", allSceneNums.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(";")));
                    sceneRspBean = sceneFeign.statisticsPoints(param, token);

                    if(null == sceneRspBean || sceneRspBean.getCode() != 0){
                        log.info("调用四维看看获取所有场景点位数失败,场景码是：" + param.get("sceneNum"));
                    }else {
                        houseVOS.get(i).setPoints(sceneRspBean.getData());
                    }
                }
            }
        }
    }



    public TmEstate getOneByNameAndBelong(String estateName , String belongCompany){
        LambdaQueryWrapper<TmEstate> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotBlank(estateName)){
            lambdaQueryWrapper.eq(TmEstate::getBelongCompanyName , belongCompany);
        }
        if(StringUtils.isNotBlank(estateName)){
            lambdaQueryWrapper.eq(TmEstate::getEstateName , estateName);
        }
        lambdaQueryWrapper.eq(TmEstate::getIsDelete , DeleteStatus.NOT_DELETE.getCode());
        lambdaQueryWrapper.last("limit 1");
        return getBaseMapper().selectOne(lambdaQueryWrapper);
    }

    public int deleteEstateById(String estateId){
        if(StringUtils.isBlank(estateId)){
            return -1;
        }
        return getBaseMapper().deleteById(estateId);
    }


    public boolean updateEstate(TmEstate estate){
        if(null == estate){
            return false;
        }
        if(null == estate.getId()){
            log.info("主键ID为空，无法更项目楼盘信息");
            return false;
        }
        estate.setUpdateTime(LocalDateTime.now());
        return saveOrUpdate(estate);
    }

    public boolean insertNew(TmEstate estate){
        if(StringUtils.isBlank(estate.getId())){
            estate.setId(SnowFlakeUUidUtils.generaUUid(null , null ,  "EST00001"));
        }
        estate.setCreateTime(LocalDateTime.now());
        estate.setUpdateTime(LocalDateTime.now());
        estate.setIsDelete(DeleteStatus.NOT_DELETE.getCode());
        return 1 == getBaseMapper().insert(estate);
    }


    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> addProject(TmEstate tmEstate, ContextTokenBean tokenMap) {
        TmEstate dbEstate = getOneByNameAndBelong(tmEstate.getEstateName(), tokenMap.getDepartmentName());
        if (null != dbEstate) {
            log.info("{}公司下面的楼盘{}已经存在", tmEstate.getBelongCompanyName(), tmEstate.getEstateName());
            throw new CommonBaseException(ResultCodeEnum.D101, "楼盘已经存在，无需再添加");
        }
        if (null != tokenMap) {
            tmEstate.setBelongCompanyId(tokenMap.getDepartmentId());
            tmEstate.setBelongCompanyName(tokenMap.getDepartmentName());
            tmEstate.setCreateById(tokenMap.getId());
            tmEstate.setCreateByName(tokenMap.getNickName());
        }
        if (insertNew(tmEstate)) {
            int ins = tmOperationService.addNewWithTypeAndContent(tokenMap , "VR楼盘项目" , "创建楼盘/" + tmEstate.getEstateName());
            if(ins != 1){
                log.error("插入操作记录失败");
            }
        }

        TmHouse tmHouse = new TmHouse();
        tmHouse.setEstateId(tmEstate.getId());
        tmHouse.setEstateName(tmEstate.getEstateName());
        if(null != tokenMap){
            tmHouse.setCreateById(tokenMap.getId());
            tmHouse.setCreateByName(tokenMap.getNickName());
        }
        tmHouse.setBelongCompanyId(tmEstate.getBelongCompanyId());
        tmHouse.setBelongCompanyName(tmEstate.getBelongCompanyName());
        tmHouse.setEstateName(tmEstate.getEstateName());
        tmHouse.setIsShow("0");
        tmHouse.setStatus(0);
        tmHouse.setType(1);
        tmHouseService.insertNew(tmHouse);
        Map<String , Object> resultMap = new HashMap<>(1);
        resultMap.put("houseId" , tmHouse.getId());
        return resultMap;
    }

    @Transactional(rollbackFor = Exception.class)
    public String delete(String estateId, ContextTokenBean contextTokenBean, String token) {
        TmEstate dbEstate = getById(estateId);
        if(null == dbEstate){
            return "楼盘不存在或已被删除";
        }

        LambdaQueryWrapper<TmHouse> qw = new LambdaQueryWrapper();
        qw.eq(TmHouse::getIsDelete, 0).eq(TmHouse::getEstateId, estateId);
        TmHouse dbHouse = tmHouseService.getOne(qw);
        if (dbHouse == null) {
            return "楼盘项目不存在或已被删除";
        }

        deleteEstateById(estateId);

        tmOperationService.addNewWithTypeAndContent(contextTokenBean , "VR楼盘项目" , "删除楼盘/" + dbEstate.getEstateName());

        if(null != dbHouse.getStatus()){
            //除了草稿、未通过状态，其他状态都不能删除
            if(!HouseStatus.canDelete(dbHouse.getStatus())){
                return "存在待审核/已审核数据，无法删除";
            }
        }

        if(!isCanDelete(dbHouse, contextTokenBean)){
            return "暂无删除权限";
        }

        int delete = tmHouseService.deleteHouseById(dbHouse.getId());

        List<TmHouse> houseList = tmHouseService.getListByEstate(estateId);
        if(!org.apache.commons.collections.CollectionUtils.isEmpty(houseList)){
            for (TmHouse house : houseList) {
                if(null != house){
                    List<String> sceneNumList = panoService.getKanKanSceneNums(house.getId() , token);
                    log.info("720返回的房源的[{}]对应的四维场景码列表为:{}" , house.getId() , JSON.toJSONString(sceneNumList));
                    if(!org.apache.commons.collections.CollectionUtils.isEmpty(sceneNumList)){
                        return "楼盘下存在未解绑的VR项目，请解绑后删除";
                    }
                }
            }
        }

        int ins = tmOperationService.addNewWithTypeAndContent(contextTokenBean , "VR楼盘项目" , "删除VR项目/" + dbHouse.getHouseTitle());

        List<String> sceneNumList = panoService.getKanKanSceneNums(dbHouse.getId() , token);
        log.info("720返回的房源的[{}]对应的四维场景码列表为:{}" , dbHouse.getId() , JSON.toJSONString(sceneNumList));
        if(!CollectionUtils.isEmpty(sceneNumList)){
            Map<String , Object> map = new HashMap<>();
            map.put("status" , 2);
            map.put("sceneNum" , sceneNumList.stream().collect(Collectors.joining(";")));
            log.info("上送四维看看的参数为:{}" , JSON.toJSONString(map));
            SceneRspBean rsp = sceneFeign.updateSceneStatus(map , token);
            log.info("四维看看翻转状态返回为:{}" , JSON.toJSONString(rsp));
            if(null == rsp || rsp.getCode() != 0){
                log.info("调用看看的更新场景状态微服务失败");
                if(null != rsp){
                    log.info("code = {} , msg = {}" , rsp.getCode() , rsp.getMsg());
                }
                throw new CommonBaseException(ResultCodeEnum.D101 , "更新看看场景状态失败");
            }

        }

        //通知720,告知房源下线(审核通过/上线:4， 下线：3)
        //panoService.noticeVrAuditStatus(houseId , getToken() , 3);

        panoService.noticeDeleteVr(dbHouse.getId(), token);
        return "删除房源成功";

    }

    /**
     * 是否可以删除的条件
     * 1.地区管理员和集团管理员、超级管理员能删除下属或自己的模型
     * 2.拍摄人员只能删除自己的模型
     * @param dbHouse
     * @return
     */
    private boolean isCanDelete(TmHouse dbHouse, ContextTokenBean contextTokenBean) {
        if (SysUserRoleEnums.REGION_SHOOT.getRoleKey().equals(contextTokenBean.getRoleKey())
                && !dbHouse.getCreateById().equals(contextTokenBean.getId())) {
            return false;
        }
        return true;
    }


}
