package com.jeeplus.test.oss.service;

import cn.hutool.core.collection.CollectionUtil;
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.core.query.QueryWrapperGenerator;
import com.jeeplus.sys.service.dto.UserDTO;
import com.jeeplus.sys.utils.UserUtils;
import com.jeeplus.test.oss.domain.WorkAttachment;
import com.jeeplus.test.oss.domain.WorkAttachmentInfo;
import com.jeeplus.test.oss.mapper.OssServiceMapper;
import com.jeeplus.test.oss.service.dto.FileDetailDTO;
import com.jeeplus.test.oss.service.dto.OssServiceDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.springframework.beans.BeanUtils;
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.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 insertWorkAttachmentInfo (WorkAttachmentInfo workAttachment, UserDTO userDto){
        ossServiceMapper.insertWorkAttachmentInfo(workAttachment, userDto);
    }

    /**
     * 保存数据
     * @param workAttachments
     * @return
     */
    public void saveMsg(List<WorkAttachment> workAttachments) {
        if (CollectionUtil.isNotEmpty(workAttachments)) {
            //获取当前登录人信息
            String id = UserUtils.getCurrentUserDTO().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());
                List<WorkAttachment> list = ossServiceMapper.selectList(lambdaQueryWrapper);
                if (CollectionUtils.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 = UserUtils.getCurrentUserDTO();
                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.deleteByMap(map);
        //项目文件删除后处理项目文件状态
        Integer num = ossServiceMapper.selectSaveById(id);
        if (num == 0) {
            ossServiceMapper.updateProjectRecord(id);
        }
        log.info("删除操作完成，共删除{}条数据" , i);
    }

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

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

    /**
     * 生成临时文件
     * @param list
     * @return
     */
    public List<WorkAttachment> temporaryUrl(List<WorkAttachment> 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();
        }
    }


}
