package com.jxy.marketall.service.impl;

import com.jxy.common.core.Result.R;
import com.jxy.common.core.text.Convert;
import com.jxy.common.core.utils.DateUtils;
import com.jxy.common.core.utils.StringUtils;
import com.jxy.common.core.web.Result.AjaxResult;
import com.jxy.common.datasource.annotation.JXYHelp;
import com.jxy.common.security.utils.SecurityUtils;
import com.jxy.marketall.dto.*;
import com.jxy.marketall.entity.JXYFile;
import com.jxy.marketall.entity.Ticket;
import com.jxy.marketall.enums.TicketStatusType;
import com.jxy.marketall.mapper.UserHelpMapper;
import com.jxy.marketall.service.UserHelpService;
import com.jxy.marketall.vo.*;
import com.jxy.system.api.RemoteFileService;
import com.jxy.system.api.entity.SysFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


/**
 * @Description ETF查询业务处理
 * @Date 2022/5/19 17:51
 * @Author 杜懿
 */
@Service
public class UserHelpServiceImpl implements UserHelpService {

    private static final Logger log = LoggerFactory.getLogger(UserHelpServiceImpl.class);

    @Autowired
    private UserHelpMapper userHelpMapper;

    @Autowired
    private RemoteFileService remoteFileService;

    public static final String FILE_PATH = "D:/marketall/uploadPath";


    @Override
    public AjaxResult getTypeList() {

        List<SelectDto> list = userHelpMapper.getTypeSelect();

        return AjaxResult.success(list);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    @JXYHelp
    public AjaxResult uploadFile(MultipartFile file) throws SQLException {
        R<SysFile> upload = remoteFileService.upload(file);

        if (StringUtils.isNull(upload) || StringUtils.isNull(upload.getData()))
        {
            return AjaxResult.error("文件服务异常，文件上传失败，请联系管理员");
        }

        SysFile sysFile = upload.getData();
        JXYFile jxyFile = new JXYFile();
        BeanUtils.copyProperties(sysFile,jxyFile);
        jxyFile.setUserName(SecurityUtils.getUsername());
        jxyFile.setFileName(sysFile.getName());

        //将文件信息存入数据库：(url、name、userName、createTime)
        boolean b = userHelpMapper.insertFileInfo(jxyFile);

        sysFile.setId(jxyFile.getId());
        if(!b){
            throw new SQLException("发生异常了..");
        }

        return AjaxResult.success(sysFile);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    @JXYHelp
    public AjaxResult uploadFiles(MultipartFile[] file) throws SQLException {

        SysFileDto dto = new SysFileDto();

        for (MultipartFile f: file) {
            R<SysFile> upload = remoteFileService.upload(f);

            if (StringUtils.isNull(upload) || StringUtils.isNull(upload.getData()))
            {
                System.out.println("gg");
                System.out.println(upload.getMsg());
                return AjaxResult.error("文件服务异常，文件上传失败");
            }

            SysFile sysFile = upload.getData();
            JXYFile jxyFile = new JXYFile();
            BeanUtils.copyProperties(sysFile,jxyFile);
            jxyFile.setUserName(SecurityUtils.getUsername());
            jxyFile.setFileName(sysFile.getName());

            //将文件信息存入数据库：(url、name、userName、createTime)
            if(!userHelpMapper.insertFileInfo(jxyFile)){
                throw new SQLException("后台异常..");
            }

            if(StringUtils.isNull(dto.getId())){
                dto.setId(Convert.toStr(jxyFile.getId()));
                dto.setUrl(jxyFile.getUrl());
                dto.setName(jxyFile.getFileName());
            }else {
                dto.setId(dto.getId()+","+jxyFile.getId());
                dto.setUrl(dto.getUrl()+","+jxyFile.getUrl());
                dto.setName(dto.getName()+","+jxyFile.getFileName());
            }

        }

        return AjaxResult.success(dto);
    }

    @Override
    public void downloadByIds(String ids, HttpServletRequest request, HttpServletResponse response){

        List<JXYFile> fileInfos = getFileInfos(ids);

        //设置响应头信息
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        //设置压缩包的名字，date为时间戳
        String date = DateUtils.dateTimeNow();
        String downloadName = "file" + date + ".zip";

        String agent = request.getHeader("USER-AGENT");
        try {
            //针对IE或者以IE为内核的浏览器：
            if (agent.contains("MSIE") || agent.contains("Trident")) {
                downloadName = URLEncoder.encode(downloadName, "UTF-8");
            } else {
                //非IE浏览器的处理：
                downloadName = new String(downloadName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            }
        } catch (Exception e) {
            log.error("系统异常", e);
        }
        response.setHeader("Content-Disposition", "attachment;fileName=" + downloadName );


        //设置压缩流：直接写入response，实现边压缩边下载
        ZipOutputStream zipOs = null;
        //循环将文件写入压缩流
        DataOutputStream os = null;
        //文件
        File file;
        try {
            zipOs = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            //设置压缩方法
            zipOs.setMethod(ZipOutputStream.DEFLATED);
            //遍历文件信息（主要获取文件名/文件路径等）
            for (JXYFile fileInfo : fileInfos) {
                //文件名（包含后缀名，如：测试.pdf）
                String name = fileInfo.getFileName();
                //本地文件路径（绝对路径，包含后缀名）
                String path = FILE_PATH + StringUtils.substringAfter(fileInfo.getUrl(), "statics");

                file = new File(path);
                if (!file.exists()) {
                    throw new RuntimeException("文件不存在");
                }
                //添加ZipEntry，并将ZipEntry写入文件流
                zipOs.putNextEntry(new ZipEntry(name));
                os = new DataOutputStream(zipOs);
                FileInputStream fs = new FileInputStream(file);
                byte[] b = new byte[100];
                int length;
                //读入需要下载的文件的内容，打包到zip文件
                while ((length = fs.read(b)) != -1) {
                    os.write(b, 0, length);
                }
                //关闭流
                fs.close();
                zipOs.closeEntry();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if (os != null) {
                    os.flush();
                    os.close();
                }
                if (zipOs != null) {
                    zipOs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public AjaxResult submitTicket(TicketVo vo) {

        Ticket ticket = new Ticket();
        ticket.setTitle(vo.getTitle());
        ticket.setTypeId(vo.getType());
        ticket.setUserName(SecurityUtils.getUsername());
        ticket.setStatus(TicketStatusType.STATUS_ONE.getCode());

        if(userHelpMapper.insertTicket(ticket)){
            //工单提交成功 把工单信息内容存入工单信息表
            ResubmitTicketVo reVo = new ResubmitTicketVo();
            //把工单问题内容和附件路径赋值到reVo
            BeanUtils.copyProperties(vo,reVo);
            //把工单id赋值到reVo
            reVo.setId(ticket.getId());
            reVo.setDesc(StringUtils.clean(reVo.getDesc()));
            return checkResult(userHelpMapper.insertTicketSupplement(reVo));
        }else {
            return AjaxResult.error(509,"服务器网络异常，提交失败");
        }

    }

    @Override
    public AjaxResult resubmitTicket(ResubmitTicketVo vo) {

        // 判断是否超过10条补充内容
        Integer num = userHelpMapper.getTicketSupplementCountByTicketId(vo.getId());
        if(userHelpMapper.checkTicketExist(vo.getId()) < 1){
            return AjaxResult.error(601,"参数错误");
        }

        if( Convert.toInt(num,0) >= 11){
            return AjaxResult.error("工单提交内容已达上限10");
        }
        //判断工单当前状态
        AjaxResult result = checkStatusById(vo.getId());
        if(StringUtils.isNotNull(result)){
            return result;
        }

        if(StringUtils.isNull(vo)){
            return  AjaxResult.error(601,"参数错误");
        }
        vo.setDesc(StringUtils.clean(vo.getDesc()));

        if(userHelpMapper.insertTicketSupplement(vo)){
            //提交成功 更改状态为用户重新提交
            userHelpMapper.changeTicketStatus(vo.getId(),TicketStatusType.STATUS_SIX.getCode());
            return AjaxResult.success("提交成功");
        }else {
            return AjaxResult.error("服务器网络异常，提交失败");
        }

    }

    @Override
    public AjaxResult readTicket(long id) {
        //更改状态为已读
        if(userHelpMapper.checkTicketExist(id) < 1){
            return AjaxResult.error(601,"参数错误");
        }

        //判断工单是否是可修改的状态
        AjaxResult result = checkStatusById(id);
        if(StringUtils.isNotNull(result)){
            return result;
        }
        return checkResult(userHelpMapper.changeTicketStatus(id,TicketStatusType.STATUS_Thirteen.getCode()));
    }

    @Override
    public AjaxResult endTicket(long id) {
        if(userHelpMapper.checkTicketExist(id) < 1){
            return AjaxResult.error(601,"参数错误");
        }
        //更改状态为已关闭 12
        return checkResult(userHelpMapper.changeTicketStatus(id,TicketStatusType.STATUS_Twelve.getCode()));
    }

    @Override
    public AjaxResult retractTicket(long id) {
        if(userHelpMapper.checkTicketExist(id) < 1){
            return AjaxResult.error(601,"参数错误");
        }
        //更改状态为撤回 2
        return checkResult(userHelpMapper.changeTicketStatus(id,TicketStatusType.STATUS_TWO.getCode()));
    }

    @Override
    public AjaxResult submitAuditTicket(long id) {
        TicketDto ticket = userHelpMapper.getTicketById(id);
        if (StringUtils.isNull(ticket)){
            return AjaxResult.error(509,"后台异常(后台网络异常/后台传参异常),信息获取失败");
        }

        //判断工单是否是可修改的状态
        AjaxResult result = checkStatusById(id);
        if(StringUtils.isNotNull(result)){
            return result;
        }
        //更改状态为待审核  8
        return checkResult(userHelpMapper.changeTicketStatus(id,TicketStatusType.STATUS_EIGHT.getCode()));
    }

    @Override
    public AjaxResult getTicketDetails(long id) {

        TicketDto ticket = userHelpMapper.getTicketById(id);
        if (StringUtils.isNull(ticket)){
            return AjaxResult.error(509,"后台异常(后台网络异常/后台传参异常),信息获取失败");
        }

        TicketDetailsDto details = new TicketDetailsDto();
        BeanUtils.copyProperties(ticket,details);
        details.setStatus(getStatus(ticket.getStatus()));

        //获取工单内容list
        List<TicketContentDto> supplementList = userHelpMapper.getTicketSupplementListByTicketId(id);

        //获取工单回复list
        List<TicketContentDto> responList = userHelpMapper.getTicketResponListByTicketId(id);

        //合并回复和内容list并重新排序
        supplementList.addAll(responList);
        List<TicketContentDto> list = supplementList.stream().sorted(Comparator.comparing(TicketContentDto::getTime)).collect(Collectors.toList());

        //list.stream().forEach(e ->{
        //    e.setFiles(getUrls(e.getFiles()));
        //});
        details.setList(list);

        TicketAuditDto audit = userHelpMapper.getTicketAuditByTicketId(id);
        details.setAudit(audit);

        //判断工单是否是可修改的状态
        AjaxResult result = checkStatusById(id);
        if(StringUtils.isNotNull(result)){
            int code = Convert.toInt(result.get("code"));
            if( code== 601){
                return result;
            }
            //工单状态为：撤回2、待审核8、审核中9、审核重新提交10、审核完成11、已关闭12的直接原样输出状态
            return AjaxResult.success(details);
        }
        List<Long> roles = new ArrayList<>();
        //管理员
        roles.add(1L);
        //支持人员
        roles.add(5L);
        if(roles.contains(SecurityUtils.getLoginUser().getSysUser().getRoleId())){
            //后台操作则修改为待处理
            //已提交1、超时未确认7则修改此时订单状态为待处理
            //已处理（仅回复但用户还未读）4、已处理(且用户已读)13、用户重新提交则不改变状态
            int status = ticket.getStatus();
            if(status == TicketStatusType.STATUS_ONE.getCode() || status == TicketStatusType.STATUS_SEVEN.getCode()){
                userHelpMapper.changeTicketStatus(id,TicketStatusType.STATUS_THREE.getCode());
                details.setStatus(TicketStatusType.STATUS_THREE.getStatus());
            }
        }

        //if(SecurityUtils.getLoginUser().getSysUser().getRoleId() == 6){
        //    userHelpMapper.changeTicketStatus(id,TicketStatusType.STATUS_NINE.getCode());
        //}

        return AjaxResult.success(details);
    }

    @Override
    public AjaxResult getPrivateTicketByStatus(int status) {

        List<TicketListDto> list = new ArrayList<>();
        if (status == 0){
            list = userHelpMapper.getPrivateTicketList(SecurityUtils.getUsername());
        }else if (status == 4){
            //已处理工单 查询状态为已处理/回复 4和 已处理 13
            list = userHelpMapper.getPrivateTicketListByStatus(SecurityUtils.getUsername(), status);
            list.addAll(userHelpMapper.getPrivateTicketListByStatus(SecurityUtils.getUsername(),TicketStatusType.STATUS_Thirteen.getCode()));
        }else if (status == 5){
            //已回复未读工单(即已处理工单) 查询状态为已处理 4和 已处理 13
            list = userHelpMapper.getPrivateTicketListByStatus(SecurityUtils.getUsername(), status);
        }else{
            return AjaxResult.success(list);
        }

        list.stream().forEach(e ->{
            e.setStatus(getStatus(Convert.toInt(e.getStatus())));
        });

        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult getUnreadCount() {
        List<TicketListDto> list = userHelpMapper.getPrivateTicketListByStatus(SecurityUtils.getUsername(), TicketStatusType.STATUS_FIVE.getCode());
        int num = list.size();
        Map<String,Integer> map = new HashMap<>();
        map.put("count",num);
        return AjaxResult.success(map);
    }


    @Override
    public AjaxResult getTicketList(int status) {

        List<TicketListDto> list = userHelpMapper.getBackendTicketList(status);

        //特殊处理1：待处理工单应该包含status为待处理、已提交和用户重新提交
        if(status == TicketStatusType.STATUS_THREE.getCode()){
            list.addAll(userHelpMapper.getBackendTicketList(TicketStatusType.STATUS_SIX.getCode()));
            list.addAll(userHelpMapper.getBackendTicketList(TicketStatusType.STATUS_ONE.getCode()));
        }

        //特殊处理2：已处理需要把用户已读 13也得包含进去
        if(status == TicketStatusType.STATUS_FOUR.getCode()){
            list.addAll(userHelpMapper.getBackendTicketList(TicketStatusType.STATUS_Thirteen.getCode()));
        }

        list.stream().forEach(e ->{
            e.setStatus(getStatus(Convert.toInt(e.getStatus())));
        });
        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult getDailyCount(QueryVo vo) {
        List<TicketDailyCountDto> list = userHelpMapper.getDailyCountList(vo);
        list.stream().forEach(t -> {t.setPendingNum(t.getSubmitNum() - t.getSolvedNum());});

        //return CheckData(list);
        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult responTicket(ResponTicketVo vo) {

        if(userHelpMapper.checkTicketExist(vo.getId()) < 1){
            return AjaxResult.error(601,"参数错误,工单不存在");
        }
        AjaxResult result = checkStatusById(vo.getId());
        if(StringUtils.isNotNull(result)){
            return result;
        }

        vo.setFiles(StringUtils.clean(vo.getFiles()));
        vo.setRespon(StringUtils.clean(vo.getRespon()));

        if(userHelpMapper.insertRespon(vo, SecurityUtils.getUsername())){
            //回复信息入库成功 修改工单状态为已处理 4 (原来的5已回复 合并)
            return checkResult(userHelpMapper.changeTicketStatus(vo.getId(), TicketStatusType.STATUS_FOUR.getCode()));
        }else {
            return AjaxResult.error("服务器网络异常，提交失败");
        }
    }

    @Override
    public AjaxResult auditTicket(AuditTicketVo vo) {
        if(userHelpMapper.checkTicketExist(vo.getId()) < 1){
            return AjaxResult.error(601,"参数错误");
        }
        if(userHelpMapper.insertAudit(vo, SecurityUtils.getUsername())){
            //审核内容添加完毕 修改工单状态为审核完毕
            return checkResult(userHelpMapper.changeTicketStatus(vo.getId(),TicketStatusType.STATUS_Eleven.getCode()));
        }else {
             return AjaxResult.error("服务器网络异常，提交失败");
        }

    }

    public AjaxResult checkResult(boolean b){
        if(!b){
            return AjaxResult.error("服务器网络异常，提交失败");
        }
        return AjaxResult.success();
    }

    /**
     * 验证list是否为空
     * @param list
     * @return
     */
    public AjaxResult CheckData(List list) {

        if(list.size() < 1){
            return AjaxResult.error(508,"后台数据获取失败，请稍后再试");
        }
        return AjaxResult.success(list);
    }

    public List<JXYFile> getFileInfos(String files){

        List<JXYFile> list = new ArrayList<>();
        if(StringUtils.isNull(files)){
            return list;
        }

        if(StringUtils.isEmpty(files)){
            return list;
        }
            Long[] ids = Convert.toLongArray(files);
            for (long id: ids) {
                JXYFile file = userHelpMapper.getFileInfoById(id);
                if(StringUtils.isNotNull(file)){
                    list.add(file);
                }
            }

        return list;

    }

    public String getStatus(int status) {

        return  TicketStatusType.getStatusByCode(status);
    }

    public AjaxResult   checkStatusById(long id){
        TicketDto ticket = userHelpMapper.getTicketById(id);
        if(StringUtils.isNull(ticket)){
            return AjaxResult.error(601,"工单id参数错误");
        }else {
            String result = checkStatusByStatusCode(ticket.getStatus());
            if(StringUtils.isNotNull(result)){
                return AjaxResult.error(result);
            }else {
                return null;
            }
        }
    }

    public String checkStatusByStatusCode(int status) {

        if(status == TicketStatusType.STATUS_Twelve.getCode()){
            return "工单已关闭，不能再操作";
        }else if(status == TicketStatusType.STATUS_EIGHT.getCode()
                || status == TicketStatusType.STATUS_NINE.getCode()
                || status == TicketStatusType.STATUS_TEN.getCode()
                || status == TicketStatusType.STATUS_Eleven.getCode()){
            return "工单审核流程后不能再执行修改操作";
        }else if(status == TicketStatusType.STATUS_TWO.getCode()) {
            return "已撤回工单不能再操作";
        }

        return  null;
    }

}
