package com.artfess.cqxy.wps.controller;

import com.artfess.base.annotation.ApiGroup;
import com.artfess.base.constants.ApiGroupConsts;
import com.artfess.base.exception.BaseException;
import com.artfess.base.model.CommonResult;
import com.artfess.base.util.HttpUtil;
import com.artfess.cqxy.universal.manager.AccessoryManager;
import com.artfess.cqxy.universal.model.Accessory;
import com.artfess.cqxy.wps.enums.FileTypeEnum;
import com.artfess.cqxy.wps.model.WpsApp;
import com.artfess.cqxy.wps.model.Url;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author 黎沐华
 * @date 2022/4/26 9:50
 */
@Slf4j
@RestController
@Api(tags = "WPS签名信息接口", description = "参数传递最好不要出现中文等特殊字符，容易导致签名不过等问题")
@ApiGroup(group = {ApiGroupConsts.GROUP_BIZ})
@RequestMapping("/wps/oauth")
public class SignatureController {

    @Autowired
    @ApiModelProperty("附件信息服务对象，获取需要的文件信息")
    private AccessoryManager accessoryManager;


    @GetMapping("/olinePreview")
    @ApiOperation("获取在线预览PDF地址")
    public CommonResult<String> getAppToken(HttpServletResponse response, @RequestParam("_w_fileid") String fileId) throws Exception {
        if (fileId == null || fileId.isEmpty()) {
            throw new BaseException("文件ID不能为空！");
        }
        Accessory accessory = accessoryManager.getById(fileId);
        if (null == accessory || StringUtils.isBlank(accessory.getUrl())) {
            throw new BaseException("抱歉，文件不存在或已经被删除！！");
        }
        String suffix = accessory.getSuffix();
        String[] arr = new String[]{"doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"};
        List<String> list = Arrays.asList(arr);
        String url = accessory.getUrl();
        String[] urlArr = url.split("/");
        String fileName = accessory.getName();
        if (list.contains(suffix)) {
            // 转换为pdf，如果已经是pdf了，则返回空值
            String filePath = accessoryManager.fileToPdf(accessory);
            // 如果filePath是空值则表示是pdf，直接使用minio下载
            if(StringUtils.isBlank(filePath)){
                filePath = accessoryManager.minIoDownFile(accessory, urlArr[4]);
                filePath = filePath + encode(accessory.getName());
            }else {
                // 否则代表转换过的文件，需要将文件名后缀名修改
                int i = fileName.lastIndexOf(".");
                if ((i > -1) && (i < (fileName.length() - 1))) {
                    filePath =  filePath + encode(fileName.substring(0, i))  + ".pdf";
                }else {
                    filePath = filePath + encode(fileName) + ".pdf";
                }
            }
//            HttpUtil.reviewFile(response, filePath, accessory.getName());
//            HttpUtil.downLoadFile(response, filePath, accessory.getName());
            return new CommonResult<String>(true,"文件地址查询成功", filePath.replace("download","/static/pdf"));
        }
//        else {
//            // 如果不是office文件或pdf则直接下载
//            accessoryManager.minIoDownFile(fileId, "default", response);
//        }
        return new CommonResult<String>(false,"当前文件格式不支持在线预览", "");
    }
    private String encode(String s) {
        String s1 = s.replace("%", "%25")
                .replace(" ", "%20")
                .replace("\"", "%22")
                .replace("#", "%23")
                .replace("&", "%26")
                .replace("(", "%28")
                .replace(")", "%29")
                .replace("+", "%2B")
                .replace(",", "%2C")
                .replace("/", "%2F")
                .replace(":", "%3A")
                .replace(";", "%3B")
                .replace("<", "%3C")
                .replace("=", "%3D")
                .replace(">", "%3E")
                .replace("?", "%3F")
                .replace("@", "%40")
                .replace("\\", "%5C")
                .replace("|", "%7C");
        return s1;
    }

    @PostMapping("/url")
    @ApiOperation("获取AppToken")
    public CommonResult getAppToken(HttpServletRequest request, @RequestParam("_w_fileid") String fileId) {
        if (fileId == null || fileId.isEmpty()) {
            return null;
        }
        Accessory one = accessoryManager.getOne(new QueryWrapper<Accessory>().eq("ID_",fileId));
        if(one.getId()!=null){
            fileId=one.getId();
        }
        String type = FileTypeEnum.getTypeBySuffix(one.getSuffix());
        String url = WpsApp.domain + "/office/" + type + "/" + fileId + "?" ;
        // 注意：签名前，参数不要urlencode,要签名以后统一处理url编码，防止签名不过，带中文等字符容易导致签名不过，要注意签名与编成的顺序，最好不要带中文等特殊字符
        Map<String, String> paramMap= new HashMap<>();
        paramMap.put("_w_appid", WpsApp.appid);
        paramMap.put("_w_fileid", fileId);
        paramMap.put("_w_tokentype","1");
        String signature = getSignature(paramMap, WpsApp.appSecret);
        url += getUrlParam(paramMap) + "&_w_signature=" + signature;
        Url urlModel = new Url(url, request.getHeader("Authorization"));
        return new CommonResult<Url>(true,"操作成功", urlModel);
    }


    /**
     * 将签名过后的 map 参数进行url编码
     *
     * @param params map参数
     * @return 编码过后的UTL
     */
    @SneakyThrows
    private String getUrlParam(Map<String, String> params) {
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (builder.length() > 0) {
                builder.append('&');
            }
            builder.append(URLEncoder.encode(entry.getKey(), "utf-8")).append('=').append(URLEncoder.encode(entry.getValue(), "utf-8"));
        }
        return builder.toString();
    }


    /**
     * 签名算法
     *
     * @param params    参与签名的参数
     * @param appSecret 签名salt，这里是WPS提供的AppKey
     * @return
     */
    private String getSignature(Map<String, String> params, String appSecret) {
        List<String> keys = new ArrayList();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            keys.add(entry.getKey());
        }

        // 将所有参数按key的升序排序
        Collections.sort(keys, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });

        // 构造签名的源字符串
        StringBuilder contents = new StringBuilder("");
        for (String key : keys) {
            if (key == "_w_signature") {
                continue;
            }
            contents.append(key + "=").append(params.get(key));
        }
        contents.append("_w_secretkey=").append(appSecret);

        // 进行hmac sha1 签名
        byte[] bytes = HmacUtils.hmacSha1(appSecret.getBytes(), contents.toString().getBytes());
        //字符串经过Base64编码
        String sign = Base64.encodeBase64String(bytes);
        try {
            sign = URLEncoder.encode(sign, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(sign);
        return sign;
    }

}
