package com.m2pool.pool.service.impl;



import com.m2pool.common.core.Result.R;
import com.m2pool.common.core.text.Convert;
import com.m2pool.common.core.utils.DateUtils;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.core.utils.file.FileTypeUtils;
import com.m2pool.common.core.web.Result.AjaxResult;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.annotation.RequiresLogin;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.pool.dto.*;
import com.m2pool.pool.entity.M2File;
import com.m2pool.pool.entity.Ticket;
import com.m2pool.pool.enums.TicketStatusType;
import com.m2pool.pool.mapper.TicketMapper;
import com.m2pool.pool.service.FileService;
import com.m2pool.pool.service.TicketService;
import com.m2pool.pool.vo.*;
import com.m2pool.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.beans.factory.annotation.Value;
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.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
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 TicketServiceImpl implements TicketService {

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

    @Autowired
    private TicketMapper ticketMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private FileService fileService;

    @Value("${myenv.filepath}")
    private String FILE_PATH ;
    //public static final String FILE_PATH = "D:/M2pool/uploadPath";

    @Value("${myenv.domain}")
    private String MY_DOMAIN;


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

        SysFileDto dto = new SysFileDto();

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

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

            SysFile sysFile = upload.getData();
            M2File m2File = new M2File();
            BeanUtils.copyProperties(sysFile, m2File);
            m2File.setUserName(SecurityUtils.getUsername());
            m2File.setFileName(StringUtils.clean(sysFile.getName()));
            System.out.println(m2File);
            String type = FileTypeUtils.getFileType(sysFile.getName()).toUpperCase();
            System.out.println("type:"+type);
            // 图片
            //"jpg", "jpeg", "png",
            //        //音频
            //        "mp3","aif", "aiff", "wav", "wma",
            //        // 视频格式
            //        "mp4", "avi", "rmvb"
            if("JPG".equals(type) || "JPEG".equals(type) ||"PNG".equals(type)){
                m2File.setFileType(0);
            }else if("MP3".equals(type) || "AIF".equals(type) ||"AIFF".equals(type) || "WAV".equals(type) || "WMA".equals(type)){
                m2File.setFileType(1);
            }else if("MP4".equals(type) || "AVI".equals(type) ||"RMVB".equals(type)){
                m2File.setFileType(2);
            }else {
                return AjaxResult.error("文件类型不在可允许范围之内");
            }

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

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

        }

        return AjaxResult.success(dto);
    }

    @Override
    public void downloadByIds(String ids, HttpServletRequest request, HttpServletResponse response) {
        List<M2File> fileInfos = getFileInfos(ids);
        System.out.println("fileInfos" + fileInfos);

        //设置响应头信息
        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 (M2File fileInfo : fileInfos) {
                //文件名（包含后缀名，如：测试.pdf）
                String name = fileInfo.getFileName();
                //本地文件路径（绝对路径，包含后缀名）
                String path = FILE_PATH + StringUtils.substringAfter(fileInfo.getUrl(), "statics");
                System.out.println("path" + path);
                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();
            }
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    @RequiresLogin
    public AjaxResult submitTicket(TicketVo vo) {

        vo.setEmail(SecurityUtils.getUsername());


        if(StringUtils.isBlank(vo.getDesc())){
            return AjaxResult.error("问题描述不能为空");
        }

        Ticket ticket = new Ticket();
        BeanUtils.copyProperties(vo, ticket);

        ticket.setStatus(TicketStatusType.STATUS_ONE.getCode());
        ticket.setEmail(SecurityUtils.getUsername());

        if (ticketMapper.insertTicket(ticket)) {
            //工单提交成功
            System.out.println("工单提交成功:"+ticket);
            //处理附件
            String  video="";
            String  audio="";
            String  image="";
            if(StringUtils.isNotBlank(vo.getFiles())){
                List<M2File> files = getFileInfos(vo.getFiles());

                for (M2File f:files) {
                    if(f.getFileType() == 0){
                        //图片  0
                        if(StringUtils.isBlank(image)){
                            image = image+f.getUrl();
                        }else {
                            image = image+","+f.getUrl();
                        }
                    }else if(f.getFileType() == 1){
                        //音频  1
                        if(StringUtils.isBlank(audio)){
                            audio = audio+f.getUrl();
                        }else {
                            audio = audio+","+f.getUrl();
                        }
                    }else if(f.getFileType() == 2){
                        //视频  2
                        if(StringUtils.isBlank(video)){
                            video = video+f.getUrl();
                        }else {
                            video = video+","+f.getUrl();
                        }
                    }
                }

            }

            ResubmitTicketVo rsVo = new ResubmitTicketVo();
            rsVo.setId(ticket.getId());
            rsVo.setDesc(vo.getDesc());
            rsVo.setFiles(vo.getFiles());
            rsVo.setAudioFiles(audio);
            rsVo.setImageFiles(image);
            rsVo.setVideoFiles(video);
            ticketMapper.insertTicketSupplement(rsVo);
            return AjaxResult.success("工单提交成功");
        } else {
            return AjaxResult.error(509, "服务器网络异常，提交失败");
        }

    }


    @Override
    @RequiresLogin
    public AjaxResult resubmitTicket(ResubmitTicketVo vo) {

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

        // 判断是否超过40条补充内容
        Integer num = ticketMapper.getTicketSupplementCountByTicketId(vo.getId());
        TicketDto ticket = ticketMapper.getTicketById(vo.getId());
        if (StringUtils.isNull(ticket)) {
            return AjaxResult.error(601, "参数错误");
        }

        if (Convert.toInt(num, 0) >= 61) {
            return AjaxResult.error("工单提交内容已达上限60");
        }
        //判断工单当前状态
        if(ticket.getStatus() == TicketStatusType.STATUS_TEN.getCode()){
            return AjaxResult.error("工单已完结,不能再继续提交,若还有问题您可以重新提交工单");
        }

        vo.setDesc(StringUtils.clean(vo.getDesc()));

        //处理files 转换为video_files/转换为image_files/转换为audio_files

        //处理附件
        String  video="";
        String  audio="";
        String  image="";
        if(StringUtils.isNotBlank(vo.getFiles())){
            List<M2File> files = getFileInfos(vo.getFiles());

            for (M2File f:files) {
                if(f.getFileType() == 0){
                    //图片  0
                    if(StringUtils.isBlank(image)){
                        image = image+f.getUrl();
                    }else {
                        image = image+","+f.getUrl();
                    }
                }else if(f.getFileType() == 1){
                    //音频  1
                    if(StringUtils.isBlank(audio)){
                        audio = audio+f.getUrl();
                    }else {
                        audio = audio+","+f.getUrl();
                    }
                }else if(f.getFileType() == 2){
                    //视频  2
                    if(StringUtils.isBlank(video)){
                        video = video+f.getUrl();
                    }else {
                        video = video+","+f.getUrl();
                    }
                }
            }

        }
        vo.setAudioFiles(audio);
        vo.setImageFiles(image);
        vo.setVideoFiles(video);

        if (ticketMapper.insertTicketSupplement(vo)) {
            //提交成功 更
            if(ticketMapper.changeTicketUpdateTime(vo.getId())){
                return AjaxResult.success("提交成功");
            }else {
                return AjaxResult.error("服务器网络异常，提交失败");
            }
        } else {
            return AjaxResult.error("服务器网络异常，提交失败");
        }
    }


    @Override
    public AjaxResult endTicket(EndTicketVo vo) {

        if (StringUtils.isNull(vo)) {
            return AjaxResult.error("参数丢失");
        }

        TicketDto ticket = ticketMapper.getTicketById(vo.getId());

        if (StringUtils.isNull(ticket)) {
            return AjaxResult.error(601, "参数错误");
        }
        if (!ticket.getEmail().equals(SecurityUtils.getUsername())) {
            return AjaxResult.error("不能修改他人的工单");
        }

        if (ticket.getStatus() == 1 || ticket.getStatus() == 2) {
            //用户可关闭工单的状态 待处理1  客服处理中2
        } else {
            return AjaxResult.error("当前状态下的工单不能关闭");
        }

        return checkResult(ticketMapper.changeTicketStatus(vo.getId(), TicketStatusType.STATUS_TEN.getCode()));
    }

    @Override
    public AjaxResult getTicketDetails(long id) {

        if (id < 1) {
            return AjaxResult.error("工单号参数缺失");
        }

        TicketPrivateDto ticket = ticketMapper.getBackendTicketById(id);
        if (StringUtils.isNull(ticket)) {
            return AjaxResult.error( "根据工单号未找到工单详情");
        }

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

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

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

        ticket.setList(list);

        //ticket.setStatus(getStatus(Convert.toInt(ticket.getStatus())));

        return AjaxResult.success(ticket);
    }

    @Override
    public AjaxResult getPrivateTicketDetails(long id) {

        if (id < 1) {
            return AjaxResult.error("工单号参数缺失");
        }

        TicketPrivateDto ticket = ticketMapper.getPrivateTicketById(id, SecurityUtils.getUsername());

        if (StringUtils.isNull(ticket)) {
            return AjaxResult.error("通过工单号：" + id + ",找不到与您对应的工单！您只能查询您个人的工单");
        }

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

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

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

        ticket.setList(list);

        //ticket.setStatus(getStatus(Convert.toInt(ticket.getStatus())));

        return AjaxResult.success(ticket);
    }

    @Override
    public List<AllTicketListDto> getAllTicket(AllTicketListVo vo) {

        List<AllTicketListDto> list = ticketMapper.getTicketListByCond(vo);
        //list.stream().forEach(e -> {
        //    e.setStatus(getStatus(Convert.toInt(e.getStatus())));
        //});

        return list;
    }

    @Override
    public AjaxResult getPrivateTicketByStatus(PrivateTicketListVo vo) {

        System.out.println(vo);
        String email = SecurityUtils.getUsername();

         //com.m2pool.chat.vo.setId(Convert.toLong(SecurityUtils.getUserId(),0L));

        List<PrivateTicketListDto> list = new ArrayList<>();
        int status = vo.getStatus();
        if (status == 0) {
            //全部工单传 0
            list = ticketMapper.getPrivateTicketList(vo, email);
        } else if (status == 1) {
            //进行中的工单
            list = ticketMapper.getPrivateProcessingTicketList(vo, email);
        } else if (status == 2) {
            //已完结工单
            list = ticketMapper.getPrivateEndTicketList(vo, email);
        } else {
            return AjaxResult.success(list);
        }

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

        return AjaxResult.success(list);
    }


    @Override
    public List<TicketListDto> getSupportTicketList(StatusVo vo) {

        if(StringUtils.isNull(vo)){
            return new ArrayList<>();
        }
        if(vo.getStatus() == 0){
            //查询全部
            List<TicketListDto> list = ticketMapper.getAllTicketList(vo );
            return list;
        }
        else if(vo.getStatus() == 1 || vo.getStatus() == 2 || vo.getStatus() == 10 ){
            //status 取值仅有1 待处理     2客服处理中 10已关闭
            List<TicketListDto> list = ticketMapper.getTicketListByStatusAndType(vo);

            //list.stream().forEach(e ->                                                                      {
            //    e.setStatus(getStatus(Convert.toInt(e.getStatus())));
            //});
            return list;
        }else {
            return new ArrayList<>();
        }


    }

    @Override
    public AjaxResult onlineResponTicket(ResponTicketVo vo) {

        if (vo.getId() < 1) {
            return AjaxResult.error(601, "工单号缺失");
        }

        TicketDto ticket = ticketMapper.getTicketById(vo.getId());

        if (StringUtils.isNull(ticket)) {
            return AjaxResult.error(601, "工单不存在");
        }

        if (ticket.getStatus() == TicketStatusType.STATUS_TEN.getCode()) {
            return AjaxResult.error("工单已完结，不能再回复");
        }

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

        String  video="";
        String  audio="";
        String  image="";
        if(StringUtils.isNotBlank(vo.getFiles())){
            List<M2File> files = getFileInfos(vo.getFiles());

            for (M2File f:files) {
                if(f.getFileType() == 0){
                    //图片  0
                    if(StringUtils.isBlank(image)){
                        image = image+f.getUrl();
                    }else {
                        image = image+","+f.getUrl();
                    }
                }else if(f.getFileType() == 1){
                    //音频  1
                    if(StringUtils.isBlank(audio)){
                        audio = audio+f.getUrl();
                    }else {
                        audio = audio+","+f.getUrl();
                    }
                }else if(f.getFileType() == 2){
                    //视频  2
                    if(StringUtils.isBlank(video)){
                        video = video+f.getUrl();
                    }else {
                        video = video+","+f.getUrl();
                    }
                }
            }

        }

        vo.setAudioFiles(audio);
        vo.setImageFiles(image);
        vo.setVideoFiles(video);


        if (ticketMapper.insertRespon(vo, SecurityUtils.getUsername())) {
            //return checkResult(ticketMapper.changeTicketStatus(com.m2pool.chat.vo.getId(), TicketStatusType.STATUS_FOUR.getCode()));
            //if(ticket.getStatus() != TicketStatusType.STATUS_TWO.getCode()){
            //    //若果是待处理工单 则修改工单状态为客服处理中
            //
            //}
            ticketMapper.changeTicketStatus(vo.getId(),TicketStatusType.STATUS_TWO.getCode());
            //回复成功 邮箱通知 异步
            //CompletableFuture.runAsync(()->{
            //        mailService.sendRespondNoticeHTMLMailMessage(ticket.getEmail(), ticket.getId());
            //});

            return AjaxResult.success("回复成功");
        } else {
            return AjaxResult.error("服务器网络异常，提交失败");
        }
    }

    @Override
    public AjaxResult closeTicket(IdVo vo) {
        TicketDto ticket = ticketMapper.getTicketById(vo.getId());

        if (StringUtils.isNull(ticket)) {
            return AjaxResult.error(601, "参数错误");
        }

        if (ticket.getStatus() == 1 || ticket.getStatus() == 2) {
            //可关闭工单的状态 待处理1  客服处理中2
        } else {
            return AjaxResult.error("当前状态下的工单不能关闭");
        }
        return checkResult(ticketMapper.changeTicketStatus(vo.getId(), TicketStatusType.STATUS_TEN.getCode()));
    }



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

    public List<M2File> getFileInfos(String files) {

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

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

        return list;

    }

    public String getStatus(int status) {

        return TicketStatusType.getStatusByCode(status);
    }


}
