package com.gic.haoban.manage.web.controller.open;

import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.BasePageInfo;
import com.gic.api.base.commons.JSONResponse;
import com.gic.api.base.commons.Page;
import com.gic.api.base.commons.ServiceResponse;
import com.gic.clerk.api.dto.AuthorizedUser;
import com.gic.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.DateUtil;
import com.gic.commons.util.PageHelperUtils;
import com.gic.commons.webapi.reponse.RestResponse;
import com.gic.enterprise.api.dto.EnterpriseDTO;
import com.gic.enterprise.api.dto.EnterpriseUsingPermissionDto;
import com.gic.enterprise.api.dto.WechatWorkServiceSetting;
import com.gic.enterprise.api.service.EnterpriseService;
import com.gic.enterprise.api.service.EnterpriseUseForbidService;
import com.gic.haoban.base.api.common.pojo.dto.WebLoginDTO;
import com.gic.haoban.common.anno.IgnoreLogin;
import com.gic.haoban.common.utils.AuthWebRequestUtil;
import com.gic.haoban.common.utils.EntityUtil;
import com.gic.haoban.manage.api.dto.*;
import com.gic.haoban.manage.api.qdto.OpenStaffInitQDTO;
import com.gic.haoban.manage.api.qdto.OpenStaffPageQDTO;
import com.gic.haoban.manage.api.service.OpenStaffApiService;
import com.gic.haoban.manage.api.service.OpenStaffImportTaskApiService;
import com.gic.haoban.manage.api.service.StaffApiService;
import com.gic.haoban.manage.api.service.StaffClerkRelationApiService;
import com.gic.haoban.manage.web.qo.open.OpenStaffQO;
import com.gic.haoban.manage.web.utils.ImportExcelUtil;
import com.gic.haoban.manage.web.vo.open.OpenClerkVO;
import com.gic.haoban.manage.web.vo.open.OpenQwAccountInfoVO;
import com.gic.haoban.manage.web.vo.open.OpenStaffVO;
import com.gic.qcloud.BucketNameEnum;
import com.gic.thirdparty.cloudfile.CloudFileUtil;
import com.gic.thirdparty.cloudfile.enums.CloudFileBusinessOptEnum;
import com.gic.thirdparty.cloudfile.enums.CloudFileTypeEnum;
import com.gic.thirdparty.cloudfile.pojo.CloudFileInfo;
import com.gic.web.common.download.DownloadTask;
import com.gic.web.common.download.DownloadTaskUtil;
import com.gic.web.common.download.constants.TaskTypeEnum;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 企微托管
 */
@RestController
@RequestMapping("/qw-open")
public class QywxOpenController {

    private static final Logger log = LogManager.getLogger(QywxOpenController.class);

    @Autowired
    private OpenStaffApiService openStaffApiService;
    @Autowired
    private StaffApiService staffApiService;
    @Autowired
    private StaffClerkRelationApiService staffClerkRelationApiService;
    @Autowired
    private EnterpriseService enterpriseService;
    @Autowired
    private OpenStaffExcelHandler openStaffExcelHandler;
    @Autowired
    private EnterpriseUseForbidService enterpriseUseForbidService;
    @Autowired
    private ClerkService clerkService ;
    @Autowired
    private OpenStaffImportTaskApiService openStaffImportTaskApiService ;

    /**
     * 托管列表
     *
     * @param qo
     * @return
     */
    @RequestMapping("open-staff-page")
    public RestResponse<Page<OpenStaffVO>> page(@RequestBody OpenStaffQO qo) {
        WebLoginDTO loginUser = AuthWebRequestUtil.getLoginUser();
        OpenStaffPageQDTO qdto = EntityUtil.changeEntityByJSON(OpenStaffPageQDTO.class, qo);
        String enterpriseId = loginUser.getEnterpriseId();
        qdto.setWxEnterpriseId(loginUser.getWxEnterpriseId());
        qdto.setEnterpriseId(enterpriseId);
        BasePageInfo basePageInfo = new BasePageInfo();
        basePageInfo.setPageNum(qo.getPageNum());
        basePageInfo.setPageSize(qo.getPageSize());
        if (null != qdto.getEndDate()) {
            qdto.setEndDate(DateUtil.getEndTimeOfDay(qdto.getEndDate()));
        }
        qdto.setLoginClerkId(loginUser.getClerkId());
        ServiceResponse<Page<OpenStaffListDTO>> pageResp = this.openStaffApiService.page(qdto, basePageInfo);
        Page<OpenStaffListDTO> page = pageResp.getResult();
        Page<OpenStaffVO> retPage = PageHelperUtils.changePageToCurrentPage(page, OpenStaffVO.class);
        if (CollectionUtils.isNotEmpty(retPage.getResult())) {
            EnterpriseDTO en = this.enterpriseService.getEnterpriseById(enterpriseId);
            retPage.getResult().forEach(o -> {
                o.setBrandName(en.getBrandName());
            });
        }
        return RestResponse.successResult(retPage);
    }

    /**
     * 托管列表导出
     *
     * @param qo
     * @return
     */
    @RequestMapping("open-staff-excel")
    public RestResponse<String> excel(@RequestBody OpenStaffQO qo) {
        WebLoginDTO loginUser = AuthWebRequestUtil.getLoginUser();
        OpenStaffPageQDTO qdto = EntityUtil.changeEntityByJSON(OpenStaffPageQDTO.class, qo);
        qdto.setWxEnterpriseId(loginUser.getWxEnterpriseId());
        qdto.setEnterpriseId(loginUser.getEnterpriseId());
        BasePageInfo basePageInfo = new BasePageInfo();
        basePageInfo.setPageNum(1);
        basePageInfo.setPageSize(1);
        if (null != qdto.getEndDate()) {
            qdto.setEndDate(DateUtil.getEndTimeOfDay(qdto.getEndDate()));
        }
        qdto.setLoginClerkId(loginUser.getClerkId());
        ServiceResponse<Page<OpenStaffListDTO>> pageResp = this.openStaffApiService.page(qdto, basePageInfo);
        final int totalCount = pageResp.getResult().getTotalCount();
        if (totalCount == 0) {
            return RestResponse.failure("9999", "导出数据条数为0");
        }
        AuthorizedUser user = new AuthorizedUser();
        user.setUserId(loginUser.getClerkId());
        user.setEnterpriseId(loginUser.getEnterpriseId());
        user.setRealName(loginUser.getClerkName());
        String fileName = "好办托管企微号";
        Date startDate = qdto.getStartDate();
        Date endDate = qdto.getEndDate();
        if (null != startDate && null != endDate) {
            fileName = "好办托管企微号" + "-" + DateUtil.formatString(startDate, "yyyy-MM-dd") + "到" + DateUtil.formatString(endDate, "yyyy-MM-dd");
        }
        // 1.组装数据查询条件
        DownloadTask task = new DownloadTask();
        task.setTaskTypeEnum(TaskTypeEnum.HAOBAN_OPEN_STAFF_LIST);
        task.setUser(user);
        task.setDataType(1);
        task.setTotalCount(totalCount);
        task.setFileName(fileName);
        task.setChannelName(TaskTypeEnum.HAOBAN_OPEN_STAFF_LIST.getName());
        task.setBucketName(BucketNameEnum.REPORT_50000.getName());
        task.setSearchDataParams(JSON.toJSONStringWithDateFormat(qdto, DatePattern.NORM_DATETIME_PATTERN));
        task.setHandler(openStaffExcelHandler);
        JSONResponse jsonResponse = DownloadTaskUtil.createDownloadTask(task);
        final String reportId;
        if (jsonResponse.isSuccess()) {
            reportId = (String) jsonResponse.getResult();
        } else {
            return RestResponse.failure("9999", jsonResponse.getErrorMessage());
        }
        return RestResponse.successResult(reportId);
    }

    /**
     * 登录初始化
     *
     * @param staffId
     * @return
     */
    @RequestMapping("login-init")
    @IgnoreLogin
    @com.gic.web.common.ano.IgnoreLogin
    public RestResponse<OpenStaffDTO> init(String staffId, @RequestParam(defaultValue = "0") int loginAgainFlag , String wxEnterpriseId , String enterpriseId) {
        WebLoginDTO loginUser = AuthWebRequestUtil.getLoginUser();
        ServiceResponse<OpenStaffDTO> staffResp = this.openStaffApiService.getByStaffId(staffId) ;
        if(null != loginUser) {
            wxEnterpriseId = loginUser.getWxEnterpriseId();
            enterpriseId = loginUser.getEnterpriseId();
            if(org.apache.commons.lang3.StringUtils.isAnyBlank(wxEnterpriseId,enterpriseId,staffId)) {
                return RestResponse.failure("9999","参数为空") ;
            }
        }else {
            // 未登录直接通过参数授权
            if(org.apache.commons.lang3.StringUtils.isAnyBlank(wxEnterpriseId,enterpriseId,staffId)) {
                return RestResponse.failure("9999","参数为空") ;
            }
            OpenStaffDTO openStaff = staffResp.getResult() ;
            if(openStaff == null) {
                return RestResponse.failure("9999","该账号非托管账号") ;
            }
            if(null != openStaff && openStaff.getStatusFlag()==1) {
                StaffDTO staff = this.staffApiService.selectById(staffId);
                openStaff.setStaffHeadImg(staff.getHeadImg());
                openStaff.setStaffName(staff.getStaffName());
                return RestResponse.successResult(openStaff) ;
            }
        }
        String checkMsg = this.check(wxEnterpriseId, enterpriseId , null != staffResp.getResult());
        if (null != checkMsg) {
            return RestResponse.failure("9999", checkMsg);
        }
        if (StringUtils.isBlank(staffId)) {
            return RestResponse.failure("9999", "请先选择成员");
        }
        StaffDTO staff = this.staffApiService.selectById(staffId);
        if (null == staff || !staff.getWxEnterpriseId().equals(wxEnterpriseId)) {
            return RestResponse.failure("9999", "成员不存在");
        }
        List<StaffClerkRelationDTO> relationList = this.staffClerkRelationApiService.listByStaffId(wxEnterpriseId, staffId);
        if (CollectionUtils.isEmpty(relationList)) {
            return RestResponse.failure("9999", "成员未关联导购");
        }
        relationList.forEach(o->{
            String clerkId = o.getClerkId() ;
            ClerkDTO clerk = this.clerkService.getclerkById(clerkId) ;
            o.setClerkType(clerk.getClerkType());
        });
        String _enterpriseId = enterpriseId ;
        relationList = relationList.stream().filter(o -> o.getClerkType() <= 1 && o.getEnterpriseId().equals(_enterpriseId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(relationList)) {
            return RestResponse.failure("9999", "成员需关联gic商户下导购");
        }
        OpenStaffInitQDTO initQDTO = new OpenStaffInitQDTO();
        initQDTO.setWxEnterpriseId(wxEnterpriseId);
        initQDTO.setEnterpriseId(enterpriseId);
        initQDTO.setStaffId(staffId);
        initQDTO.setLoginAgainFlag(loginAgainFlag);
        ServiceResponse<OpenStaffDTO> resp = this.openStaffApiService.init(initQDTO);
        if (!resp.isSuccess()) {
            return RestResponse.failure("9999", resp.getMessage());
        }
        OpenStaffDTO openStaffDTO = resp.getResult();
        openStaffDTO.setStaffHeadImg(staff.getHeadImg());
        openStaffDTO.setStaffName(staff.getStaffName());
        return RestResponse.successResult(openStaffDTO);
    }

    /**
     * 获取账号详情
     *
     * @param openStaffId
     * @return
     */
    @RequestMapping("get-open-staff")
    @IgnoreLogin
    @com.gic.web.common.ano.IgnoreLogin
    public RestResponse<OpenStaffDTO> getOpenStaff(Long openStaffId) {
        ServiceResponse<OpenStaffDTO> resp = this.openStaffApiService.getById(openStaffId);
        if (!resp.isSuccess()) {
            return RestResponse.failure("9999", resp.getMessage());
        }
        OpenStaffDTO openStaffDTO = resp.getResult();
        StaffDTO staff = this.staffApiService.selectById(openStaffDTO.getStaffId());
        openStaffDTO.setStaffHeadImg(staff.getHeadImg());
        openStaffDTO.setStaffName(staff.getStaffName());
        return RestResponse.successResult(openStaffDTO);
    }

    /**
     * 校验验证码
     *
     * @param openStaffId
     * @param code
     * @return
     */
    @RequestMapping("check-code")
    @IgnoreLogin
    @com.gic.web.common.ano.IgnoreLogin
    public RestResponse<Void> checkCode(Long openStaffId, String code) {
        ServiceResponse<Void> resp = this.openStaffApiService.checkCode(openStaffId, code);
        if (!resp.isSuccess()) {
            String msg = resp.getMessage();
            if(!msg.contains("需重新获取登录码")) {
                msg = "验证码错误" ;
            }
            return RestResponse.failure("9999", msg);
        }
        return RestResponse.successResult();
    }

    /**
     * 获取2次验证二维码
     *
     * @param openStaffId
     * @return
     */
    @RequestMapping("get-2qrcode")
    public RestResponse<OpenStaffDTO> get2Qrcode(Long openStaffId) {
        ServiceResponse<OpenStaffDTO> resp = this.openStaffApiService.get2Qrcode(openStaffId);
        if (!resp.isSuccess()) {
            return RestResponse.failure("9999", resp.getMessage());
        }
        return RestResponse.successResult(resp.getResult());
    }

    /**
     * 许可数量查询
     */
    @RequestMapping("license-info")
    public RestResponse<OpenQwAccountInfoVO> licenseInfo() {
        WebLoginDTO login = AuthWebRequestUtil.getLoginUser();
        String wxEnterpriseId = login.getWxEnterpriseId();
        String enterpriseId = login.getEnterpriseId();
        OpenQwAccountInfoVO vo = this.getCheckInfo(wxEnterpriseId, enterpriseId);
        return RestResponse.successResult(vo);
    }

    /**
     * 删除托管
     *
     * @return
     */
    @RequestMapping("del-open-staff")
    public RestResponse<Void> delOpenStaff(Long openStaffId) {
        ServiceResponse<Void> resp = this.openStaffApiService.delete(openStaffId);
        if (!resp.isSuccess()) {
            return RestResponse.failure("9999", resp.getMessage());
        }
        return RestResponse.successResult();
    }

    /**
     * 取消授权
     *
     * @return
     */
    @RequestMapping("cancel-open-staff")
    public RestResponse<Void> cancelOpenStaff(Long openStaffId) {
        ServiceResponse<Void> resp = this.openStaffApiService.logout(openStaffId);
        if (!resp.isSuccess()) {
            return RestResponse.failure("9999", resp.getMessage());
        }
        return RestResponse.successResult();
    }

    private String check(String wxEnterpriseId, String enterpriseId , boolean useFlag) {
        OpenQwAccountInfoVO vo = this.getCheckInfo(wxEnterpriseId, enterpriseId);
        if (vo.getStatus() == 0) {
            return "请联系商务经理购买服务后再进行账号托管";
        }
        if (vo.getStatus() == 2) {
            return "当前企微服务已过期";
        }
        if(!useFlag) {
            if (vo.getGicTotal() <= vo.getUseNum()) {
                return "托管账号数量已达上线";
            }
        }
        return null;
    }

    private OpenQwAccountInfoVO getCheckInfo(String wxEnterpriseId, String enterpriseId) {
        OpenQwAccountInfoVO vo = new OpenQwAccountInfoVO();
        ServiceResponse<EnterpriseUsingPermissionDto> resp = this.enterpriseUseForbidService.getWxEnterpriseService(enterpriseId, wxEnterpriseId);
        log.info("托管许可={}", JSONObject.toJSONString(resp));
        if (resp.isSuccess()) {
            EnterpriseUsingPermissionDto dto = resp.getResult();
            if (null == dto) {
                vo.setStatus(0);
            } else {
                vo.setExpireDate(dto.getServiceEndDate());
                vo.setStatus(1);
                if (dto.getServiceEndDate().before(new Date())) {
                    vo.setStatus(2);
                }
                String json = dto.getModuleSetting();
                WechatWorkServiceSetting bo = JSONObject.parseObject(json, WechatWorkServiceSetting.class);
                vo.setGicTotal(bo.getAccountNumber());
                vo.setVersion(dto.getModuleVersion());
            }
        }
        ServiceResponse<OpenStaffLicenseDTO> hbResp = this.openStaffApiService.getLicenseInfo(wxEnterpriseId, enterpriseId);
        vo.setUseNum(hbResp.getResult().getUseNum());
        vo.setValidNum(hbResp.getResult().getValidNum());
        log.info("OpenQwAccountInfoVO={}", JSONObject.toJSONString(vo));
        return vo;
    }


    /**
     * 导购授权
     * @param wxEnterpriseId
     * @param enterpriseId
     * @param clerkCode
     * @return
     */
    @IgnoreLogin
    @com.gic.web.common.ano.IgnoreLogin
    @RequestMapping("open-qrcode-for-clerk")
    public RestResponse<OpenClerkVO> cancelOpenStaff(String wxEnterpriseId , String enterpriseId , String clerkCode) {
        if(org.apache.commons.lang3.StringUtils.isAnyBlank(wxEnterpriseId,enterpriseId,clerkCode)) {
            return RestResponse.failure("9999","参数为空") ;
        }
        ClerkDTO clerk = this.clerkService.getClerkByClerkCode(enterpriseId,clerkCode) ;
        if(null == clerk) {
            return RestResponse.failure("9999","该账号在当前企业下不存在") ;
        }
        if(clerk.getClerkType() > 1) {
            return RestResponse.failure("9999","非导购") ;
        }
        String clerkId = clerk.getClerkId() ;
        StaffClerkRelationDTO staffClerkRelationDTO = this.staffClerkRelationApiService.getByClerkId(clerkId) ;
        if(null == staffClerkRelationDTO) {
            return RestResponse.failure("9999","该账号未绑定好办小程序") ;
        }
        String staffId = staffClerkRelationDTO.getStaffId() ;
        OpenClerkVO vo  = new OpenClerkVO() ;
        vo.setClerkId(clerkId);
        vo.setStoreId(clerk.getStoreId());
        vo.setStaffId(staffId);
        return RestResponse.successResult(vo);
    }


    /**
     * 导入账号
     * @param file
     * @return
     * @throws Exception
     */
    @RequestMapping(path = "/import-open-staff")
    public RestResponse<?> importVirtualStock(@RequestParam("file") MultipartFile file) throws Exception {
        WebLoginDTO login = AuthWebRequestUtil.getLoginUser();
        String wxEnterpriseId = login.getWxEnterpriseId();
        String enterpriseId = login.getEnterpriseId();
        String checkMsg = this.check(wxEnterpriseId, enterpriseId , false);
        if (null != checkMsg) {
            return RestResponse.failure("9999", checkMsg);
        }
        List<List<Object>> result = new ArrayList<>();
        ImportExcelUtil.getBankListByExcelSheet1(file.getInputStream(), file.getOriginalFilename(), result);
        if (CollectionUtils.isEmpty(result) || result.size() <= 1) {
            return RestResponse.failure("9999", "文件内容为空");
        }
        // 判断是否超过数量
        if (result.size() > 5000) {
            return RestResponse.failure("9999", "最多导入 1000 条信息，文件大小不超过 2 M");
        }
        List<Object> columns = result.get(0) ;
        if(CollectionUtils.isEmpty(columns)) {
            return RestResponse.failure("9999", "请上传正确的导入模板");
        }
        log.info("标题={}", JSONObject.toJSONString(columns));
        if(null==columns.get(0) || !columns.get(0).toString().toLowerCase().trim().equals("导购code")) {
            log.info("{}",columns.get(0));
            return RestResponse.failure("9999", "请上传正确的导入模板");
        }
        List<String> clerkCodeList = new ArrayList<>();
        for (int i = 1; i < result.size(); i++) {
            List<Object> objects = result.get(i);
            if(CollectionUtils.isEmpty(objects)) {
                continue;
            }
            log.info("解析第 {}行数据 {} , {}", (i + 1), JSON.toJSONString(objects) , objects.size());
            String content = objects.stream().map(o->o.toString().trim()).collect(Collectors.joining(""));
            if(org.apache.commons.lang3.StringUtils.isBlank(content)) {
                continue ;
            }
            String cardNum = (objects.get(0) == null) ? "" : objects.get(0).toString() ;
            if(org.apache.commons.lang3.StringUtils.isNotBlank(cardNum)) {
                clerkCodeList.add(cardNum) ;
            }
        }
        if (CollectionUtils.isEmpty(clerkCodeList)) {
            return RestResponse.failure("9999", "导入文件无数据");
        }

        File excelFile = File.createTempFile("tmp", null);
        FileUtils.copyInputStreamToFile(file.getInputStream(), excelFile);
        EnterpriseDTO en = this.enterpriseService.getEnterpriseById(enterpriseId) ;
        String fileName = file.getOriginalFilename();
        CloudFileInfo uploadInfo = CloudFileUtil.uploadTempFile(excelFile,  fileName.substring(fileName.lastIndexOf(".") + 1), CloudFileTypeEnum.FILE, en.getFactoryCode() , CloudFileBusinessOptEnum.TASK_CENTER, 365L) ;
        log.info("上传返回的实体信息为:{}",uploadInfo);
        String sourceUrl = null ;
        if (uploadInfo != null) {
            sourceUrl = uploadInfo.getOrgFileUrl() ;
        }
        OpenStaffImportDTO qdto = new OpenStaffImportDTO() ;
        qdto.setWxEnterpriseId(wxEnterpriseId);
        qdto.setEnterpriseId(enterpriseId);
        qdto.setLoginClerkId(login.getClerkId());
        qdto.setClerkCodeList(clerkCodeList);
        qdto.setLoginName(login.getClerkName());
        qdto.setRealName(login.getClerkName());
        qdto.setSourceUrl(sourceUrl);
        ServiceResponse<String> serviceResponse = this.openStaffImportTaskApiService.createTask(qdto);
        log.info("批量导入导购任务结果 result:{}", JSON.toJSONString(serviceResponse));
        excelFile.delete();
        if (serviceResponse.isSuccess()) {
            return RestResponse.successResult(serviceResponse.getResult());
        }
        return RestResponse.failure(serviceResponse.getCode(), serviceResponse.getMessage());
    }

}
