package com.fdkankan.ucenter.controller.app;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONObject;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.constant.SceneConstant;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.*;
import com.fdkankan.fyun.face.FYunFileServiceInterface;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.constant.RedisLockKey;
import com.fdkankan.redis.util.RedisLockUtil;
import com.fdkankan.sign.AesUtil;
import com.fdkankan.ucenter.annotation.VerifySign;
import com.fdkankan.ucenter.common.BaseController;
import com.fdkankan.ucenter.common.Result;
import com.fdkankan.ucenter.common.constants.ConstantFilePath;
import com.fdkankan.ucenter.common.constants.NacosProperty;
import com.fdkankan.ucenter.constant.CameraConstant;
import com.fdkankan.ucenter.constant.LoginConstant;
import com.fdkankan.ucenter.entity.*;
import com.fdkankan.ucenter.service.*;
import com.fdkankan.ucenter.service.impl.LoginService;
import com.fdkankan.ucenter.service.impl.SceneApiService;
import com.fdkankan.ucenter.util.DateUserUtil;
import com.fdkankan.ucenter.vo.request.AppGoEditScenePage;
import com.fdkankan.ucenter.vo.request.LoginParam;
import com.fdkankan.ucenter.vo.request.RequestSceneStatistics;
import com.fdkankan.ucenter.vo.response.LoginVo;
import com.fdkankan.ucenter.vo.response.SceneInfoVo;
import com.fdkankan.ucenter.vo.response.UserVo;
import java.io.File;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.apache.bcel.generic.RET;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/ucenter/scene")
public class SceneApiController extends BaseController {

    @Autowired
    ISceneProService sceneProService;
    @Autowired
    IScenePlusService scenePlusService;
    @Autowired
    IScenePlusExtService scenePlusExtService;
    @Autowired
    IUserService userService;
    @Autowired
    LoginService loginService;
    @Autowired
    ICameraService cameraService;
    @Autowired
    ICameraDetailService cameraDetailService;
    @Autowired
    ISceneCooperationService cooperationService;
    @Autowired
    private IScene3dNumService scene3dNumService;
    @Autowired
    private ISceneStatisticsService sceneStatisticsService;
    @Autowired
    private RedisLockUtil redisLockUtil;
    @Autowired
    private ISceneProEditService sceneProEditService;
    @Autowired
    private FYunFileServiceInterface fYunFileService;
    @Autowired
    SceneApiService sceneApiService;
    @Autowired
    private IInnerService innerService;

    @Value("${scene.pro.url}")
    private String sceneProUrl;

    @Value("${scene.pro.new.url}")
    private String sceneProNewUrl;

    @Value("${scene.v4.url}")
    private String sceneProV4Url;


    /**
     * 获取指定场景信息
     * @param num 场景码
     */
    @RequestMapping("/getInfo")
    public Result getInfo(@RequestParam(required = false) String num){
        return Result.success( sceneProService.getInfo(num) );
    }


    //app 使用跳转到编辑页面
    @PostMapping("/goEditScenePage")
    @VerifySign
    public Result goEditScenePage(@RequestBody AppGoEditScenePage appGoEditScenePage) {
        String phoneNum = appGoEditScenePage.getPhoneNum();
        String password = appGoEditScenePage.getPassword();
        String sceneNum = appGoEditScenePage.getSceneNum();
        String childName = appGoEditScenePage.getChildName();
        String lang = appGoEditScenePage.getLang();
        String vlog = appGoEditScenePage.getVlog();
        String pad = appGoEditScenePage.getPad();
        log.info("goEditScenePage---param--phoneNum:{},password:{},sceneNum:{},childName:{},lang:{},vlog:{},pad:{}",
                phoneNum,password,sceneNum,childName,lang,vlog,pad);

        ScenePro scene = sceneProService.getByNum(sceneNum);
        ScenePlus scenePlus = null;
        if(scene == null){
             scenePlus = scenePlusService.getByNum(sceneNum);
        }
        if(scene == null && scenePlus == null) {
            throw new BusinessException(SceneConstant.FAILURE_CODE_5005, SceneConstant.FAILURE_MSG_5005);
        }
        Long userId = scene == null ? scenePlus.getUserId() : scene.getUserId();

        String webSite = scene == null ? scenePlusExtService.getByPlusId(scenePlus.getId()).getWebSite()  : scene.getWebSite();

        if(StringUtils.isNotEmpty(childName)){
            Camera cameraEntity = cameraService.getByChildName(childName);
            if(cameraEntity != null){
                CameraDetail cameraDetailEntity = cameraDetailService.getByCameraId(cameraEntity.getId());
                if(cameraDetailEntity != null && cameraDetailEntity.getCooperationUser() != null){
                    throw new BusinessException(SceneConstant.FAILURE_CODE_5014, SceneConstant.FAILURE_MSG_5014);
                }
                UserVo user = new UserVo();
                if(userId == null){
                    user.setUserName(childName);
                    user.setCameraLogin(1);
                    user.setCameraId(cameraEntity.getId());
                }else {
                    User dbUser = userService.getById(userId);
                    BeanUtils.copyProperties(dbUser,user);
                }

                return sendResponse(user,webSite, request,response,sceneNum,lang,vlog, pad);
            }
        }

        if(StringUtils.isEmpty(phoneNum) || StringUtils.isEmpty(password)
                || StringUtils.isEmpty(sceneNum)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }

        if(userId == null) {
            throw new BusinessException(SceneConstant.FAILURE_CODE_5013, SceneConstant.FAILURE_MSG_5013);
        }
        User user = userService.getByUserName(phoneNum);
        if(user == null){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3015, LoginConstant.FAILURE_MSG_3015);
        }
        UserVo ssoUser =  new UserVo();
        BeanUtils.copyProperties(user,ssoUser);

        if(!ssoUser.getId().equals(userId)) {
            HashMap<String, List<User>> cooMap = cooperationService.getByNumList(Arrays.asList(sceneNum),"mesh");
            List<User> cooUsers = cooMap.get(sceneNum);
            if(cooUsers == null || cooUsers.isEmpty()){
                throw new BusinessException(SceneConstant.FAILURE_CODE_5014, SceneConstant.FAILURE_MSG_5014);
            }
            List<Long> collect = cooUsers.stream().map(User::getId).collect(Collectors.toList());
            if(!collect.contains(ssoUser.getId())){
                throw new BusinessException(SceneConstant.FAILURE_CODE_5014, SceneConstant.FAILURE_MSG_5014);
            }

        }
        String passwordCode = null;
        try {
            passwordCode = SecurityUtil.MD5(AesUtil.desEncrypt(password));
        } catch (Exception e) {
            throw new BusinessException(LoginConstant.FAILURE_CODE_3014, LoginConstant.FAILURE_MSG_3014);
        }
        if(!passwordCode.equals(ssoUser.getPassword())) {
            throw new BusinessException(LoginConstant.FAILURE_CODE_3014, LoginConstant.FAILURE_MSG_3015);
        }
        return sendResponse(ssoUser,webSite, request,response,sceneNum,lang,vlog, pad);

    }

    private Result sendResponse(UserVo user, String webSite, HttpServletRequest request,
                              HttpServletResponse response, String sceneNum, String lang, String vlog, String pad) {
        String token = loginService.redisLogin(user.getUserName(),JSONObject.toJSONString(user),"user");
        //登录成功
        String mainUrl = NacosProperty.getMainUrl();
        if(StringUtils.isBlank(mainUrl)){
            mainUrl = "http://"+request.getRemoteHost() +"/";
        }

        try {
            String redirect  = null;
            if(webSite.contains(sceneProUrl)){
                 redirect = mainUrl + sceneProUrl.replace("show", "edit").replace("PC", "Mobile") +
                        sceneNum + "&t=" +System.currentTimeMillis() + "&token=" + token + "&app" +
                        (lang == null ? "" : "&lang=" + lang) + (vlog == null ? "" : "&vlog=" + vlog);
            }

            if(webSite.contains(sceneProV4Url)){
                 redirect = mainUrl + sceneProV4Url.replace("s", "e") +
                        sceneNum + "&t=" +System.currentTimeMillis() + "&token=" + token + "&app" +
                        (lang == null ? "" : "&lang=" + lang) + (vlog == null ? "" : "&vlog=" + vlog) + (StrUtil.isEmpty(pad) ? "" : "&pad");
            }

            if(webSite.contains(sceneProNewUrl)) {
                 redirect = mainUrl + sceneProNewUrl.replace("s", "e") +
                        sceneNum + "&t=" + System.currentTimeMillis() + "&token=" + token + "&app" +
                        (lang == null ? "" : "&lang=" + lang) + (vlog == null ? "" : "&vlog=" + vlog);

            }
            log.info("goEditScenePage---response--website:{},redirect:{}", webSite,redirect);
            return Result.success("操作成功",redirect);
        }catch (Exception e){
            e.printStackTrace();
        }
        return Result.failure("获取跳转链接失败");
    }

    //app调用 跳转到官网消费页面
    @PostMapping("/goConsumptionPage")
    @VerifySign
    public Result goConsumptionPage(@RequestBody AppGoEditScenePage appGoEditScenePage){
        String phoneNum = appGoEditScenePage.getPhoneNum();
        String password = appGoEditScenePage.getPassword();
        String lang = appGoEditScenePage.getLang();
        log.info("phoneNum:{},password:{},lang:{}",phoneNum,password,lang);

        if(StringUtils.isEmpty(phoneNum) || StringUtils.isEmpty(password)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        LoginParam param = new LoginParam();
        param.setPhoneNum(phoneNum);
        param.setPassword(password);
        LoginVo loginVo = loginService.loginClear(param);
        //登录成功
        String mainUrl = NacosProperty.getMainUrl();
        if(StringUtils.isBlank(mainUrl)){
            mainUrl = "http://"+request.getRemoteHost() +"/";
        }
        return Result.success("操作成功",mainUrl+ "mobile.html?token="+ loginVo.getToken() + "&app" + (lang == null ? "" : "&lang=" + lang)+"#/consumption/0" );
    }

    /**
     * 查找123看房未使用过的场景吗
     * */
    @PostMapping("/finSkSceneNum")
    @VerifySign
    public Result finSkSceneNum(){
        String num = scene3dNumService.generateSceneNum(null);
        return Result.success(num);
    }

    /**
     * 查找八目未使用过的场景吗*
     * */
    @PostMapping("/finSceneNum")
    @VerifySign
    public Result finSceneNum(){
        String num = scene3dNumService.generateSceneNum(null);
        return Result.success(num);
    }

    /**
     * 根据时间场景码等获取百度统量
     * @param param
     * @return
     */
   // @PostMapping(value = "/statistics/findByTime")
    public Result findByTime(@RequestBody RequestSceneStatistics param){

        if(org.springframework.util.StringUtils.isEmpty(param.getSceneNum()) || param.getType() == null ||
            org.springframework.util.StringUtils
                .isEmpty(param.getStartDate()) || org.springframework.util.StringUtils.isEmpty(param.getEndDate())){
            throw new BusinessException(ErrorCode.FAILURE_CODE_3001);
        }

        return Result.success(sceneStatisticsService.findByTime(
            DateUtil.string2Date(param.getStartDate(), DateUtil.YYYYMMDD_DATA_FORMAT),
            DateUtil.string2Date(param.getEndDate(), DateUtil.YYYYMMDD_DATA_FORMAT),
            param.getSceneNum(), param.getType()));
    }

    /**
     * 下载思为的html页面
     */
    @GetMapping(value = "/downloadSiWeiHtml")
    public Result downloadSiWeiHtml(HttpServletRequest request) throws Exception{
        String token = getToken();
        if(StringUtils.isEmpty(token)){
            throw new BusinessException(ErrorCode.FAILURE_CODE_3004);
        }

        User user = userService.getByToken(token);
        if(user == null){
            throw new BusinessException(ErrorCode.FAILURE_CODE_3004);
        }

        String sceneNum = request.getParameter("sceneNum");
        if(StringUtils.isEmpty(sceneNum)){
            throw new BusinessException(ErrorCode.FAILURE_CODE_3001);
        }

        //获取getInfo的数据
        ScenePro sceneProEntity = sceneProService.getByNum(sceneNum);
        if(sceneProEntity == null){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }
        if(sceneProEntity.getPayStatus() != 1){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }
        if(sceneProEntity.getStatus() != 1 && sceneProEntity.getStatus() != -2){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }

        if(user.getId().longValue() != sceneProEntity.getUserId().longValue()){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5014);
        }

        boolean lock = redisLockUtil.lock(RedisLockKey.LOCK_DOWNLOAD_SIWEI_HTML, RedisKey.EXPIRE_TIME_2_HOUR);
        if(!lock){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5024, SceneConstant.FAILURE_MSG_5024);
        }

        try{
            SceneInfoVo responseScene = new SceneInfoVo();
            SceneProEdit editEntity = sceneProEditService.getByProId(sceneProEntity.getId());

            FileUtil.copyContent(new File(ConstantFilePath.BASE_PATH + "/local/localHose"), new File(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum), true);

            //14表示matterPro场景，需要调用命令获取切图，并且修改sceneScheme为13
            if(sceneProEntity.getSceneSource() == 14){
                sceneProEntity.setSceneScheme(13);
                RuntimeUtil.execForStr("node /opt/4dkankan_scene/index.js -s " + sceneProEntity.getNum() + " -d " + ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum);
            }

            BeanUtils.copyProperties(editEntity, responseScene);
            BeanUtils.copyProperties(sceneProEntity, responseScene);
            if(StrUtil.isNotEmpty(editEntity.getEntry())){
                responseScene.setEntry(JSONObject.parseObject(editEntity.getEntry()).toJSONString());
            }

            if(StrUtil.isNotEmpty(sceneProEntity.getGps())){
                responseScene.setGps(JSONObject.parseObject(sceneProEntity.getGps()).toJSONString());
            }

            responseScene.setCreateTime(sceneProEntity.getCreateTime());
            responseScene.setCreateDate(DateExtUtil.parse(sceneProEntity.getCreateTime(), DateExtUtil.dateStyle).getTime());
            if(StrUtil.isEmpty(editEntity.getSceneKey())){
                responseScene.setIsPublic(0);
            }else {
                responseScene.setIsPublic(1);
            }

            //不返回场景访问密码
            responseScene.setSceneKey("");

            //替换index.html里面的场景码
            String indexPath = ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + File.separator + "embed.html";
            String index = FileUtils.readFile(indexPath);
            FileUtils.deleteFile(indexPath);
            FileUtils.writeFile(indexPath, index.replace("__ProjectNum__", sceneNum));

            //下载oss资源
            fYunFileService.downloadFileByCommand(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + "/data", "data/data" + sceneNum);
            fYunFileService.downloadFileByCommand(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + "/images", "images/images" + sceneNum);
            fYunFileService.downloadFileByCommand(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + "/video", "video/video" + sceneNum);
            fYunFileService.downloadFileByCommand(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + "/voice", "voice/voice" + sceneNum);

            FileUtils.writeFile(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + "/data/data" + sceneNum + "/getInfo.json",
                JSONObject.toJSONString(responseScene));

            ZipUtil.zip(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum,  ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum + ".zip");

            FileUtils.deleteDirectory(ConstantFilePath.BASE_PATH + "/local/localHose" + sceneNum);

            return Result.success((Object)"local/localHose" + sceneNum + ".zip");
        }catch (Exception e){
            log.error("思维下载失败，num=" + sceneNum, e);
            return Result.failure(LoginConstant.ERROR_MSG);
        }finally {
            redisLockUtil.unlockLua(RedisLockKey.LOCK_DOWNLOAD_SIWEI_HTML);
        }

    }


    /**
     * 内部使用查询场景名称和场景码
     */
    @RequestMapping(value = "/getScenesBySnCode", method = RequestMethod.GET)
    @VerifySign
    public Result getScenesBySnCode(String snCode) throws Exception{
        return sceneApiService.getScenesBySnCode(snCode,getToken());
    }

    /**
     * 思为获取场景列表
     */
    @RequestMapping(value = "/siweiSceneList", method = RequestMethod.GET)
    public Result siweiSceneList(HttpServletRequest request) throws Exception{
        return Result.success(sceneApiService.siweiSceneList(request,getToken()));
    }

    /**
     * 场景浏览
     * @return
     */
    //@RequestMapping(value = "/loadAllScene", method = RequestMethod.POST)
    public Result loadAllScene(@RequestBody JSONObject param) throws Exception {
        return Result.success(sceneApiService.loadAllScene(param));
    }

    /**
     * 增加场景下载次数
     */
    //@RequestMapping(value = "/addDownloadNum", method = RequestMethod.GET)
    public Result addDownloadNum(HttpServletRequest request) throws Exception{
        sceneApiService.addDownloadNum(request.getParameter("sceneNum"));
        return Result.success();
    }

    /**
     * 获取编辑页面的资源下载路径
     */
    @RequestMapping(value = "/getEditDataUrl")
    @VerifySign
    public Result getEditDataUrl(HttpServletRequest request) throws Exception{
        List<String> result = sceneApiService.getEditDataUrl(request.getParameter("num"));
        return Result.success(result);
    }

    /**
     * 查询场景资源路径
     */
    @GetMapping("/querySceneDataSource")
    @VerifySign
    public String querySceneDataSource(String num){
        return innerService.querySceneDataSource(num);
    }

    /**
     *
     * 获取场景描述等信息
     */
    @RequestMapping(value = "/getSceneDetail", method = RequestMethod.GET)
    public Result getSceneDetail(String sceneNum) throws Exception{
        String token = getToken();
        if(StringUtils.isEmpty(token)){
            throw new BusinessException(3004, "无token参数");
        }
        User user = userService.getByToken(token);
        if(user == null){
            throw new BusinessException(3004, "token参数不正确");
        }

        if(StringUtils.isEmpty(sceneNum)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }

        ScenePro pro = sceneProService.getByNum(sceneNum);
        ScenePlus plus = scenePlusService.getByNum(sceneNum);
        if(pro == null && plus == null){
            throw new BusinessException(SceneConstant.FAILURE_CODE_5005, SceneConstant.FAILURE_MSG_5005);
        }
        Long cameraId = pro == null ? plus.getCameraId() : pro.getCameraId();
        String snCode = null;
        if(!ObjectUtils.isEmpty(cameraId)){
            Camera cameraEntity = cameraService.getById(cameraId);
            if(ObjectUtils.isEmpty(cameraEntity)){
                throw new BusinessException(CameraConstant.FAILURE_CODE_6029, CameraConstant.FAILURE_MSG_6029);
            }
            snCode = cameraEntity.getSnCode();
        }
        Map<String, Object> map = new HashMap<>();
        String webSite = null;
        String thumb = null;
        String sceneName = null;
        String sceneDec = null;
        String createDate = null;

        if(pro != null){
            webSite = pro.getWebSite();
            thumb = pro.getThumb();
            sceneName = pro.getSceneName();
            sceneDec = pro.getSceneDec();
            createDate = pro.getCreateTime();
        }
        if(plus != null){
            sceneName = plus.getTitle();
            createDate = plus.getCreateTime();
            sceneDec = plus.getDescription();
            ScenePlusExt plusExt = scenePlusExtService.getByPlusId(plus.getId());
            if(plusExt != null){
                webSite = plusExt.getWebSite();
                thumb = plusExt.getThumb();
            }
        }

        map.put("webSite", webSite);
        map.put("thumb", thumb);
        map.put("num", sceneNum);
        map.put("sceneName", sceneName);
        map.put("sceneDec", sceneDec);
        map.put("snCode", snCode);
        map.put("createDate", DateUserUtil.getDate(createDate).getTime());
        map.put("createTime", createDate);
        return Result.success(map);
    }

}
