package com.dcsoft.system.visitor.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.dcsoft.common.core.constant.CacheConstants;
import com.dcsoft.common.core.constant.Constants;
import com.dcsoft.common.core.exception.ServiceException;
import com.dcsoft.common.core.utils.CollUtil;
import com.dcsoft.common.core.utils.SmsUtils;
import com.dcsoft.common.core.utils.poi.ExcelUtil;
import com.dcsoft.common.core.web.controller.BaseController;
import com.dcsoft.common.core.web.domain.AjaxResult;
import com.dcsoft.common.core.web.page.TableDataInfo;
import com.dcsoft.common.log.annotation.Log;
import com.dcsoft.common.log.enums.BusinessType;
import com.dcsoft.common.redis.service.RedisService;
import com.dcsoft.common.security.annotation.RequiresPermissions;
import com.dcsoft.common.sms.config.properties.SmsProperties;
import com.dcsoft.system.domain.SysPeople;
import com.dcsoft.system.domain.vo.IdNamelVo;
import com.dcsoft.system.service.ISysDictDataService;
import com.dcsoft.system.service.ISysPeopleService;
import com.dcsoft.system.utils.UuidUtil;
import com.dcsoft.system.visitor.domain.*;
import com.dcsoft.system.visitor.service.IVisCarryStuffService;
import com.dcsoft.system.visitor.service.IVisVisitorExamineService;
import com.dcsoft.system.visitor.service.IVisitorService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/stuff")
public class VisCarryStuffController  extends BaseController {


    @Resource
    private IVisCarryStuffService visCarryStuffService;

    @Autowired
    private ISysDictDataService dictDataService;

    @Autowired
    private ISysPeopleService sysPeopleService;

    @Autowired
    private VisitorController visitorController;

    @Autowired
    private IVisitorService visitorService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private SmsProperties smsProperties;

    @Autowired
    private IVisVisitorExamineService visVisitorExamineService;

    private static final String APPROVE_KEY = "APPROVE_KEY:STUFF_APPROVE";


    @GetMapping("/list")
    public TableDataInfo list(VisExitOutVo vo) {
        startPage();
        List<VisExitOutVo> list = visCarryStuffService.selectList(vo);
        if (CollUtil.isEmpty(list)) {
            return getDataTable(list);
        }

        //查询物品信息列表
        List<Long> collect = list.stream().map(VisExitOutVo::getId).collect(Collectors.toList());
        VisStuffInfoVo visStuffInfoVo = new VisStuffInfoVo();
        visStuffInfoVo.setExitIds(collect);
        List<VisStuffInfoVo> stuffList = visCarryStuffService.selectStuffList(visStuffInfoVo);
        if (CollUtil.isEmpty(stuffList)) {
            return getDataTable(list);
        }

        //处理字典值
        Map<String, String> map = dictDataService.queryDictData("vis_out_stuff_type");
        stuffList.forEach(stuff -> {
            if (StrUtil.isNotBlank(stuff.getType())) {
                stuff.setTypeName(map.get(stuff.getType()));
            }
            if (StrUtil.isNotBlank(stuff.getBackType())) {
                stuff.setBackTypeName(map.get(stuff.getBackType()));
            }
            if (StrUtil.isNotBlank(stuff.getImgUrls())) {
                stuff.setImgUrlList(Arrays.asList(stuff.getImgUrls().split(",")));
            }
            if (StrUtil.isNotBlank(stuff.getBackImgUrls())) {
                stuff.setBackImgUrlList(Arrays.asList(stuff.getBackImgUrls().split(",")));
            }
        });

        //构造数据
        Map<Long, List<VisStuffInfoVo>> collect1 = stuffList.stream().collect(Collectors.groupingBy(VisStuffInfoVo::getExitId));
        list.forEach(exit -> {
            exit.setVisStuffInfoList(collect1.get(exit.getId()));
        });

        return getDataTable(list);
    }

    /**
     * 获取携物信息详细信息（详情）
     */
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        VisExitOutVo stuffVo = visCarryStuffService.selectVisExitOutById(id);

        //查询物品信息列表
        VisStuffInfoVo visStuffInfoVo = new VisStuffInfoVo();
        visStuffInfoVo.setExitId(stuffVo.getId());
        List<VisStuffInfoVo> stuffList = visCarryStuffService.selectStuffList(visStuffInfoVo);
        if (CollUtil.isNotEmpty(stuffList)) {
            //处理字典
            Map<String, String> map = dictDataService.queryDictData("vis_out_stuff_type");
            stuffList.forEach(stuff -> {
                if (StrUtil.isNotBlank(stuff.getType())) {
                    stuff.setTypeName(map.get(stuff.getType()));
                }
                if (StrUtil.isNotBlank(stuff.getBackType())) {
                    stuff.setBackTypeName(map.get(stuff.getBackType()));
                }
                if (StrUtil.isNotBlank(stuff.getImgUrls())) {
                    stuff.setImgUrlList(Arrays.asList(stuff.getImgUrls().split(",")));
                }
                if (StrUtil.isNotBlank(stuff.getBackImgUrls())) {
                    stuff.setBackImgUrlList(Arrays.asList(stuff.getBackImgUrls().split(",")));
                }
            });
            stuffVo.setVisStuffInfoList(stuffList);
        }

        //查询二维码信息
        CheckCodeVo codeVo = visCarryStuffService.selectStuffCheckCode(id);
        if (ObjectUtil.isNotNull(codeVo)) {
            stuffVo.setQrCode(codeVo.getCode());
        }

        //查询审核信息
        List<VisitorReviewProcessVo> reviewProcess = visCarryStuffService.queryVisitorReviewProcessList(id);
        if(CollUtil.isNotEmpty(reviewProcess)) {
            stuffVo.setReviewProcessList(reviewProcess);
        }
        return success(stuffVo);
    }


    /**
     * 新增访客信息
     */
    @Log(title = "出门证申请", businessType = BusinessType.INSERT)
    @PostMapping
    @Transactional
    public AjaxResult add(@Validated @RequestBody VisExitOutVo vo) {
        log.info("新增出门证申请信息：{}", vo);
        //校验是否存在返厂物资
        List<VisStuffInfoVo> visStuffInfoList = vo.getVisStuffInfoList();
        for (VisStuffInfoVo visStuffInfoVo : visStuffInfoList) {
            if (visStuffInfoVo.getIsBack() == 1) {
                vo.setIsExistBack(1);
                if (visStuffInfoVo.getBackNumber() > visStuffInfoVo.getNumber()) {
                    throw new ServiceException("返厂物资数量不能大于出厂物资数量！");
                }
            }
        }

        try {
            //新增出门申请
            visCarryStuffService.insertVisExitOut(vo);

            //新增物资信息
            visStuffInfoList.forEach(stuff -> stuff.setExitId(vo.getId()));
            visCarryStuffService.insertVisStuffInfo(visStuffInfoList);
        } catch (Exception e) {
            log.error("出门证申请add异常：", e);
            throw new ServiceException("系统异常，请重新提交或联系管理员！");
        }

        // 通知一级审核人，企微发送消息（小程序来源）
        SysPeople people = sysPeopleService.selectSysPeopleById(vo.getReviewer1());

        String url = getExamineUrl(String.valueOf(vo.getId()), people.getPhone());
        log.info("出门证申请add发送：{}审核链接：{}", people.getPhone(), url);

        //发送企微信息
        try {
            visitorController.sendWeCom(people.getPhone(), url + " --访客姓名：" + vo.getName());
        } catch (Exception e) {
            log.error("出门证申请add-sendWeCom异常：", e);
            throw new ServiceException("系统异常，请重新提交或联系管理员！");
        }

        return AjaxResult.success();
    }

    /**
     * 获取审核链接
     *
     * @return
     */
    public String getExamineUrl(String id, String telephone) {
        //生成8位短参作为缓存key
        String code = UuidUtil.getShortUuid();
        try {
            while (redisService.hasKey(code)) {
                code = UuidUtil.getShortUuid();
            }
            redisService.setCacheObject(CacheConstants.VIS_CARRY_STUFF_CODE + code, id + "&" + telephone, 30L, TimeUnit.DAYS);
        } catch (Exception e) {
            throw new ServiceException("缓存数据异常：" + e.getMessage());
        }
        return "https://fk.xyxaks.cn/h5/?c=" + code + "2";
    }

    /**
     * 生成出门证编号
     * @return
     */
    @PostMapping("/getExitPermitNo")
    public AjaxResult getExitPermitNo() {
        return AjaxResult.success("操作成功", System.currentTimeMillis() + SmsUtils.generateSmsCode());
    }

    /**
     * 流程审核
     */
    @Log(title = "携物流程审核", businessType = BusinessType.UPDATE)
    @PostMapping("/approve")
    @Transactional
    public AjaxResult approve(@RequestBody VisExitOutVo vo) {
        log.info("携物流程审核入参 {}", JSON.toJSONString(vo));
        try {
            String telephone = StringUtils.isBlank(vo.getTelephone()) ? "1" : vo.getTelephone();
            Boolean lock = redisService.lock(APPROVE_KEY, telephone, 60 * 5, TimeUnit.SECONDS);
            if (!lock) {
                log.error("approve-审核人员正在审核中");
                return error("正在审核中");
            }

            //查询当前审核人基本信息
            SysPeople sysPeople = sysPeopleService.queryPeopleName(telephone, null);

            //查询出门证申请详情信息
            VisExitOutVo stuffVo = visCarryStuffService.selectVisExitOutById(vo.getId());

            //保存审核环节表
            vo.setReviewer(sysPeople.getId());
            vo.setState(vo.getExamineState());
            visCarryStuffService.saveVisitorReviewProcess(vo);

            //保存审核历史表
            VisVisitorExamine examine = new VisVisitorExamine();
            examine.setExitId(vo.getId());
            examine.setCreateBy(sysPeople.getName());
            examine.setExamine(vo.getExamineState());

            //审核通过
            SysPeople people = new SysPeople();
            if(Constants.ZERO.equals(vo.getExamineState())) {
                //一级审核人审核
                if (stuffVo.getCurrentNode() == 1) {
                    vo.setExamineState("2");
                    vo.setCurrentNode(2);
                    //查询二级审核人信息，发送审核链接
                    people = sysPeopleService.selectSysPeopleById(stuffVo.getReviewer2());
                }
                //二级审核人审核
                else if (stuffVo.getCurrentNode() == 2) {
                    vo.setExamineState("2");
                    vo.setCurrentNode(3);
                    //查询三级审核人信息，发送审核链接
                    people = sysPeopleService.selectSysPeopleById(stuffVo.getReviewer3());
                }
                else {//三级审核，最后一级
                    //保存审核历史表
                    visVisitorExamineService.insertVisVisitorExamine(examine);

                    // 保存审核二维码地址信息
                    CheckCodeVo codeVo = new CheckCodeVo();
                    codeVo.setCode(vo.getId() + "&time=" + new Date().getTime());
                    codeVo.setExitId(String.valueOf(vo.getId()));
                    codeVo.setId(UUID.randomUUID().toString().replace("-", ""));
                    visitorService.saveVisCheckCode(codeVo);
                }
            }

            //向下级审核人发送审核信息
            String url = getExamineUrl(String.valueOf(vo.getId()), people.getPhone());
            log.info("出门证申请appove发送：{}审核链接：{}", people.getPhone(), url);

            //发送企微信息
            try {
                visitorController.sendWeCom(people.getPhone(), url + " --访客姓名：" + vo.getName());
            } catch (Exception e) {
                log.error("出门证申请add-sendWeCom异常：", e);
                throw new ServiceException("系统异常，请重新提交或联系管理员！");
            }

            //审核拒绝
            if (Constants.ONE.equals(vo.getExamineState())) {
                //保存审核历史表
                visVisitorExamineService.insertVisVisitorExamine(examine);

                try {
                    visitorController.sendWeCom(telephone, vo.getName() + "的访客审核已驳回");
                } catch (Exception e) {
                    log.error("访客approve-sendWeCom驳回异常", e);
                }
                // 申请人发送短信（审核不通过）
                SysPeople sysPeople1 = sysPeopleService.selectSysPeopleById(stuffVo.getUserId());
                visitorController.sendMessage(sysPeople1.getPhone(), "1",  smsProperties.getTemplate3());
            }

            visCarryStuffService.updateStaff(vo);
            return toAjax(true);
        } catch (Exception e) {
            log.error("审核异常:", e);
            throw new ServiceException("审核异常");
        }finally {
            redisService.deleteObject(APPROVE_KEY);
        }
    }

    /**
     * 查询审核人下拉数据
     * @return
     */
    @PostMapping("/getReviewerSelect")
    public AjaxResult getReviewerSelect(@RequestBody SysPeople people) {
        people.setBranchId("0");
        List<SysPeople> peopleList = sysPeopleService.selectSysPeopleLists(people);
        List<IdNamelVo> list = new ArrayList<>();
        peopleList.forEach(item -> {
            IdNamelVo vo = new IdNamelVo();
            vo.setId(item.getId());
            vo.setName(item.getName());
            list.add(vo);
        });
        return AjaxResult.success(list);
    }

    /**
     * 导出出门证信息列表
     */
    @RequiresPermissions("visitor:stuff:export")
    @Log(title = "出门证申请", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, VisExitOutVo vo) {
        List<VisStuffInfoExportVo> list = visCarryStuffService.selectVisitorList(vo);
        Map<String, String> map = dictDataService.queryDictData("vis_out_stuff_type");
        list.forEach(stuff -> {
            if (StrUtil.isNotBlank(stuff.getType())) {
                stuff.setTypeName(map.get(stuff.getType()));
            }
            if (StrUtil.isNotBlank(stuff.getBackType())) {
                stuff.setBackTypeName(map.get(stuff.getBackType()));
            }
            if (StrUtil.isNotBlank(stuff.getImgUrls())) {
                String[] split = stuff.getImgUrls().split(",");
                for (int i = 0; i < split.length; i++) {
                    if (i == 0) {
                        stuff.setImgUrls1(split[i]);
                    }
                    if (i == 1) {
                        stuff.setImgUrls2(split[i]);
                    }
                    if (i == 2) {
                        stuff.setImgUrls3(split[i]);
                    }
                }
            }
        });
        ExcelUtil<VisStuffInfoExportVo> util = new ExcelUtil<>(VisStuffInfoExportVo.class);
        util.exportExcel(response, list, "出厂物资明细数据");
    }

}
