package com.jeeplus.pubmodules.oss.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.SimplifiedObjectMeta;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeeplus.common.TokenProvider;
import com.jeeplus.core.query.QueryWrapperGenerator;
import com.jeeplus.pubmodules.oss.domain.WorkAttachment;
import com.jeeplus.pubmodules.oss.mapper.OssServiceMapper;
import com.jeeplus.pubmodules.oss.service.dto.AttachmentDTO;
import com.jeeplus.pubmodules.oss.service.dto.FileDetailDTO;
import com.jeeplus.pubmodules.oss.service.dto.FileUrlDto;
import com.jeeplus.pubmodules.oss.service.dto.WorkAttachmentDto;
import com.jeeplus.sys.domain.WorkAttachmentInfo;
import com.jeeplus.sys.feign.IUserApi;
import com.jeeplus.sys.service.dto.UserDTO;
import com.jeeplus.sys.service.dto.WorkAttachmentInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OssService extends ServiceImpl<OssServiceMapper, WorkAttachment> {

    @Value("${config.accessory.aliyun.aliyunUrl}")
    private String aliyunUrl;

    @Value("${config.accessory.aliyun.aliyunDownloadUrl}")
    private String aliyunDownloadUrl;

    @Value("${config.accessory.aliyun.endpoint}")
    private String endpoint;

    @Value("${config.accessory.aliyun.accessKeyId}")
    private String accessKeyId;

    @Value("${config.accessory.aliyun.accessKeySecret}")
    private String accessKeySecret;

    @Value("${config.accessory.aliyun.bucketName}")
    private String bucketName;

    @Resource
    private OssServiceMapper ossServiceMapper;

    @Value("${aliyun_directory}")
    private String directory = "attachment-file/assess";

    @Resource
    private OSSClientService ossClientService;

    public void insertWorkAttachment (WorkAttachment workAttachment, UserDTO userDto){
        ossServiceMapper.insertWorkAttachment(workAttachment, userDto);
    }


    /**
     * 保存数据
     * @param workAttachments
     * @return
     */
    public void saveMsg(List<WorkAttachment> workAttachments,String currentToken) {
//        String currentToken = TokenProvider.getCurrentToken();
        if (CollectionUtil.isNotEmpty(workAttachments)) {
            //获取当前登录人信息
            String id = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken).getId();
            int i = 1;
            for (WorkAttachment workAttachment : workAttachments) {
                //判断文件是否存在
                /*LambdaQueryWrapper<WorkAttachment> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(WorkAttachment::getUrl, workAttachment.getUrl());
                lambdaQueryWrapper.eq(WorkAttachment::getAttachmentId, workAttachment.getAttachmentId());*/
                WorkAttachmentInfo workAttachmentInfo = new WorkAttachmentInfo();
                workAttachmentInfo.setUrl(workAttachment.getUrl());
                workAttachmentInfo.setAttachmentId(workAttachment.getAttachmentId());
                List<WorkAttachmentInfo> list = ossServiceMapper.getByAttachmentIdAndUrlAndAttachmentFlag(workAttachmentInfo);
                if (CollectionUtil.isNotEmpty(list)) {
                    i++;
                    continue;
                }
                log.info("开始执行保存操作，入参：{}" , JSONObject.toJSONString(workAttachments));
                //文件后缀名赋值
                List<String> strings = Arrays.asList(workAttachment.getUrl().split("\\."));
                workAttachment.setType(strings.get(strings.size()-1));
                workAttachment.setId(UUID.randomUUID().toString().replace("-",""));
                //排序赋值
                workAttachment.setSort(i);
                //基础信息赋值
                //workAttachment.getCreateBy().setId(id);
                workAttachment.setCreateTime(new Date());
                //workAttachment.getUpdateBy().setId(id);
                workAttachment.setUpdateTime(new Date());
                workAttachment.setDelFlag(0);
                i++;

                UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
                ossServiceMapper.insertWorkAttachment(workAttachment, userDTO);
            }


            log.info("保存操作执行完成");
        }
    }

    /**
     * 根据文件路径删除文件
     * @param url
     */
    public void deleteMsgByFileName(String url) {
        log.info("开始执行删除操作，入参：{}" , url);
        Map<String,Object> map = new HashMap<>();
        map.put("url", url);
        int i = ossServiceMapper.deleteByMap(map);
        log.info("删除操作完成，共删除{}条数据" , i);
    }

    /**
     * 根据id删除数据
     * @param id
     */
    public void deleteMsgById(String id) {
        log.info("开始执行删除操作，入参：{}" , id);
        Map<String,Object> map = new HashMap<>();
        map.put("id", id);
        int i = ossServiceMapper.deleteById(id);
        //项目文件删除后处理项目文件状态
        Integer num = ossServiceMapper.selectSaveById(id);
        if (num == 0) {
            ossServiceMapper.updateProjectRecord(id);
        }
        log.info("删除操作完成，共删除{}条数据" , i);
    }

    /**
     * 根据附件对应父节点id查询文件列表
     * @param attachmentId
     * @return
     */
    public List<AttachmentDTO> findFileList(String attachmentId) {

        log.info("文件查询开始，入参：{}" , attachmentId);
        QueryWrapper<WorkAttachment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq ("a.attachment_id", attachmentId );
        queryWrapper.eq ("a.del_flag", "0" );
        List<AttachmentDTO> list = ossServiceMapper.findList(queryWrapper);
        //创建人和文件名称处理
        if (CollectionUtil.isNotEmpty(list)) {
            temporaryUrl(list);
        }
        log.info("文件查询结束，查询结果：{}" , JSONObject.toJSONString(list));
        return list;
    }

    /**
     * 生成临时文件
     * @param list
     * @return
     */
    public List<AttachmentDTO> temporaryUrl(List<AttachmentDTO> list) {
        list.stream().forEach(work -> {
            String url = null;
            if (StringUtils.isNotEmpty(work.getUrl())) {
                url = aliyunUrl + work.getUrl();
                work.setTemporaryUrl(getFileTemporaryLookUrl(url));
            }

            //对文件大小进行处理
            if(StringUtils.isBlank(work.getFileSize())){
                work.setFileSize("0");
            }
            if(StringUtils.isNotBlank(work.getFileSize())){
                Long fileSizeBytes = Long.parseLong(work.getFileSize());
                //如果数据库文件大小小于等于0， 则访问阿里云获取文件大小
                fileSizeBytes = 0L;
                if (fileSizeBytes<=0){
                    fileSizeBytes = ossClientService.getSimplifiedObjectMeta(url);
                }

                if(null != fileSizeBytes){
                    Double fileSize = (double)fileSizeBytes/1024/1024;
                    work.setFileSize(String.format("%.2f", fileSize));
                }else{
                    work.setFileSize("0.00");
                }
            }
        });
        return list;
    }

    /**
     * 根据文件路径获取文件信息
     * @param url
     * @return
     */
    public FileDetailDTO getFileSizeByUrl(String url){
        FileDetailDTO fileDetailDTO = new FileDetailDTO();
        fileDetailDTO.setUrl(getFileTemporaryLookUrl(aliyunUrl + url));
        Long fileSizeBytes = ossClientService.getSimplifiedObjectMeta(aliyunUrl + url);
        if(null != fileSizeBytes){
            Double fileSize = (double)fileSizeBytes;
            fileDetailDTO.setSize(String.format("%.2f", fileSize));
        }else{
            fileDetailDTO.setSize("0");
        }
        return fileDetailDTO;
    }

    /**
     * 阿里云获取临时文件查看url
     * @param url
     */
    public String getFileTemporaryLookUrl(String url){
        url = url.replace("amp;","");
        String cons = "";
        if (url.contains(aliyunUrl)){
            cons = aliyunUrl;
        }else if (url.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")){
            cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
        }else {
            cons = aliyunDownloadUrl;
        }
        String key = "";
        String[] split = url.split(cons + "/");
        if(split.length>1){
            key = split[1];
        }else{
            key = url;
        }
        // 指定过期时间为24小时。
        Date expiration = new Date(new Date().getTime() + 1000 * 60 * 60 * 24 );
        //初始化OSSClient
        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
        return ossClient.generatePresignedUrl(bucketName, key, expiration).toString();
    }

    /**
     * 附件下载
     * @param key
     * @param fileName
     * @param response
     */
    public void downByStream(String key, String fileName, HttpServletResponse response, String agent){
        try {
            String newName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20").replaceAll("%28", "\\(").replaceAll("%29", "\\)").replaceAll("%3B", ";").replaceAll("%40", "@").replaceAll("%23", "\\#").replaceAll("%26", "\\&").replaceAll("%2C", "\\,");
            // 创建OSSClient实例
            //初始化OSSClient
            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
            OSSObject ossObject = ossClient.getObject(bucketName, key);
            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            response.setHeader("Content-Disposition","attachment;filename*=UTF-8''"+ newName);

            /*if(agent != null && agent.toLowerCase().indexOf("firefox") > 0){
                response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''"+ URLEncoder.encode(fileName,"utf-8"));
            }else {
                response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
            }*/
            byte[] car=new byte[1024];
            int L=0;
            while((L=in.read(car))!=-1){
                out.write(car, 0,L);
            }
            if(out!=null){
                out.flush();
                out.close();
            }
            if(in!=null){
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 上传文件
     * @param file
     * @param dir 存放文件夹名称
     * @return
     * @throws Exception
     */
    public FileUrlDto webUpload(MultipartFile file, String dir) throws IOException {
        FileUrlDto dto = new FileUrlDto();
        // 文件保存路径
        String fileDir =directory+"/"+dir+ossClientService.datePath()+"/"+ System.currentTimeMillis();
        // 判断文件是否为空
        if (!file.isEmpty()) {
            String name = file.getOriginalFilename ();
            ossClientService.uploadFile2OSS(file.getInputStream(), fileDir, name);
            String url = fileDir +name;
            String lsUrl = this.getFileTemporaryLookUrl(aliyunUrl + "/" + fileDir +name);
            dto.setUrl(url);
            dto.setLsUrl(lsUrl);
        }
        return dto;
    }

    /**
     * 保存/修改附件
     * @param fileList 要保存的附件，传空值则删除attachmentId下的所有附件
     * @param attachmentId 附件的attachmentId
     * @param attachmentFlag 附件的attachmentFlag
     */
    public void saveOrUpdateFileList(List<WorkAttachmentDto> fileList, String attachmentId, String attachmentFlag,String currentToken){
//        String currentToken = TokenProvider.getCurrentToken();

        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
        if (CollectionUtil.isNotEmpty(fileList)) {
            List<String> ids = fileList.stream().filter(item -> {
                if (StringUtils.isNotBlank(item.getId())) {
                    return true;
                }
                return false;
            }).map(WorkAttachmentDto::getId).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(ids)){
                ossServiceMapper.delete(new QueryWrapper<WorkAttachment>().lambda()
                        .eq(WorkAttachment::getAttachmentId, attachmentId)
                        .notIn(WorkAttachment::getId,ids));
            }else{
                ossServiceMapper.delete(new QueryWrapper<WorkAttachment>().lambda()
                        .eq(WorkAttachment::getAttachmentId, attachmentId));
            }

            List<WorkAttachmentDto> dtoList = fileList.stream().filter(item -> {
                if (StringUtils.isNotBlank(item.getId())) {
                    return false;
                }
                return true;
            }).collect(Collectors.toList());

            this.saveFileList(dtoList, userDTO, attachmentId,attachmentFlag);
        } else {
            ossServiceMapper.delete(new QueryWrapper<WorkAttachment>().lambda().eq(WorkAttachment::getAttachmentId, attachmentId));
        }
    }

    /**
     * 保存/修改附件
     * @param fileList 要保存的附件，传空值则删除attachmentId下attachmentFlag下的所有附件
     * @param attachmentId 附件的attachmentId
     * @param attachmentFlag 附件的attachmentFlag
     */
    public void saveOrUpdateFileListFlag(List<WorkAttachmentInfoDTO> fileList, String attachmentId, String attachmentFlag,String currentToken){

//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//        String bearerToken = authentication.getCredentials().toString();

        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
        if (CollectionUtil.isNotEmpty(fileList)) {
            List<String> ids = fileList.stream().filter(item -> {
                if (StringUtils.isNotBlank(item.getId())) {
                    return true;
                }
                return false;
            }).map(WorkAttachmentInfoDTO::getId).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(ids)){
                ossServiceMapper.delete(new QueryWrapper<WorkAttachment>().lambda()
                        .eq(WorkAttachment::getAttachmentId, attachmentId)
                        .eq(WorkAttachment::getAttachmentFlag, attachmentFlag)
                        .notIn(WorkAttachment::getId,ids));
            }else{
                ossServiceMapper.delete(new QueryWrapper<WorkAttachment>().lambda()
                        .eq(WorkAttachment::getAttachmentId, attachmentId)
                        .eq(WorkAttachment::getAttachmentFlag, attachmentFlag));
            }

            List<WorkAttachmentInfoDTO> dtoList = fileList.stream().filter(item -> {
                if (StringUtils.isNotBlank(item.getId())) {
                    return false;
                }
                return true;
            }).collect(Collectors.toList());

            this.saveFileList2(dtoList, userDTO, attachmentId,attachmentFlag);
        } else {
            ossServiceMapper.delete(new QueryWrapper<WorkAttachment>().lambda().eq(WorkAttachment::getAttachmentId, attachmentId).eq(WorkAttachment::getAttachmentFlag, attachmentFlag));
        }
    }

    /**
     * 保存附件信息
     * @param list 待保存的附件列表
     * @param userDTO 当前登录用户
     * @param attachmentId 关联id
     */
    public void saveFileList2(List<WorkAttachmentInfoDTO> list, UserDTO userDTO, String attachmentId,String attachmentFlag) {
        int sort = 1;
        for (WorkAttachmentInfoDTO dto : list) {
            WorkAttachment i = new WorkAttachment();
            //包含了url、size、name
            i.setId(UUID.randomUUID().toString().replace("-", ""));
//            i.getCreateBy().setId(userDTO.getId());
            i.setCreateTime(new Date());
//            i.getUpdateBy().setId(userDTO.getId());
            i.setUpdateTime(new Date());
            i.setDelFlag(0);
            i.setUrl(dto.getUrl());
            //文件类型处理
            List<String> strings = Arrays.asList(dto.getName().split("\\."));
            if (CollectionUtil.isNotEmpty(strings)) {
                i.setType(strings.get(1));
            }
            i.setAttachmentId(attachmentId);
            i.setAttachmentName(dto.getName());
            i.setAttachmentFlag(attachmentFlag);
            i.setFileSize(dto.getSize());
            i.setSort(sort);
            ossServiceMapper.insertWorkAttachment(i, userDTO);
            sort++;
        }
    }

    /**
     * 保存附件信息
     * @param list 待保存的附件列表
     * @param userDTO 当前登录用户
     * @param attachmentId 关联id
     */
    public void saveFileList(List<WorkAttachmentDto> list, UserDTO userDTO, String attachmentId,String attachmentFlag) {
        int sort = 1;
        for (WorkAttachmentDto dto : list) {
            WorkAttachment i = new WorkAttachment();
            //包含了url、size、name
            i.setId(UUID.randomUUID().toString().replace("-", ""));
//            i.getCreateBy().setId(userDTO.getId());
            i.setCreateTime(new Date());
//            i.getUpdateBy().setId(userDTO.getId());
            i.setUpdateTime(new Date());
            i.setDelFlag(0);
            i.setUrl(dto.getUrl());
            //文件类型处理
            List<String> strings = Arrays.asList(dto.getName().split("\\."));
            if (CollectionUtil.isNotEmpty(strings)) {
                i.setType(strings.get(1));
            }
            i.setAttachmentId(attachmentId);
            i.setAttachmentName(dto.getName());
            i.setAttachmentFlag(attachmentFlag);
            i.setFileSize(dto.getSize());
            i.setSort(sort);
            ossServiceMapper.insertWorkAttachment(i, userDTO);
            sort++;
        }
    }

    /**
     * 保存附件信息
     * @param workAttachmentDto 待保存的附件信息
     * @param userDTO 当前登录用户
     * @param attachmentId 关联id
     * @param attachmentFlag
     * @param sort
     */
    public String saveFile(WorkAttachmentDto workAttachmentDto, UserDTO userDTO, String attachmentId,String attachmentFlag, Integer sort) {
        WorkAttachment i = new WorkAttachment();
        //包含了url、size、name
        i.setId(UUID.randomUUID().toString().replace("-", ""));
        i.setCreateTime(new Date());
        i.setUpdateTime(new Date());
        i.setDelFlag(0);
        i.setUrl(workAttachmentDto.getUrl());
        //文件类型处理
        List<String> strings = Arrays.asList(workAttachmentDto.getName().split("\\."));
        if (CollectionUtil.isNotEmpty(strings)) {
            i.setType(strings.get(1));
        }
        i.setAttachmentId(attachmentId);
        i.setAttachmentName(workAttachmentDto.getName());
        i.setAttachmentFlag(attachmentFlag);
        i.setFileSize(workAttachmentDto.getSize());
        i.setSort(sort);
        ossServiceMapper.insertWorkAttachment(i, userDTO);
        return i.getId();
    }

    public List<WorkAttachmentInfo> selectWorkAttachmentByAttachmentId (String id){
        return ossServiceMapper.selectWorkAttachmentByAttachmentId(id);
    }


    public void deleteById(String id) {
        ossServiceMapper.deleteById(id);
    }

    /**
     * 根据attachmentId删除附件
     * @param attachmentId
     */
    public void deleteByAttachmentId(String attachmentId) {
        ossServiceMapper.deleteByAttachmentId(attachmentId);
    }

    public List<WorkAttachmentInfo> selectListByAttachmentId(String attachmentId) {
        return ossServiceMapper.selectListByAttachmentId(attachmentId);
    }

    public List<WorkAttachmentInfo> getByAttachmentIdAndUrlAndAttachmentFlag(WorkAttachmentInfo workattachment) {

        return ossServiceMapper.getByAttachmentIdAndUrlAndAttachmentFlag(workattachment);
    }

    public void deleteByAttachmentIdNotInIds(String attachmentId, List<String> delIds) {
        ossServiceMapper.deleteByAttachmentIdNotInIds(attachmentId,delIds);
    }
}
