package com.malk.service.dingtalk.impl;

import cn.hutool.core.util.ObjectUtil;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.dingtalk.DDClient_Storage;
import com.malk.utils.UtilMap;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 储存管理
 *
 * @apiNote https://open.dingtalk.com/document/orgapp/dingtalk-storage-overview
 */
@Service
@Slf4j
public class DDImplClient_Storage implements DDClient_Storage {

    ///////////////////////// 钉盘附件 /////////////////////////

    // ppExt 最大50. 参数不能为1, nextToken 传递后第二次调用就返回为空
    private static final int maxResults = 50;

    /**
     * 新建空间
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/new-space
     */
    @Override
    public DDR_New createSpaces(String accessToken, String name, String unionId) {
        return null;
    }

    /**
     * 获取空间列表
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/queries-a-space-list
     */
    @Override
    public List<Map> getSpaces(String accessToken, String unionId) {

        return _getSpaces(accessToken, unionId, maxResults, null, new ArrayList<>());
    }

    /// 递归空间列表
    private List<Map> _getSpaces(String accessToken, String unionId, int maxResults, String nextToken, List<Map> dataList) {

        // spaceType: 空间类型。org：企业空间
        Map param = UtilMap.map("unionId, spaceType, maxResults, nextToken", unionId, "org", maxResults, nextToken);
        DDR_New ddr_new = DDR_New.doGet("https://api.dingtalk.com/v1.0/drive/spaces", DDConf.initTokenHeader(accessToken), param);
        dataList.addAll(ddr_new.getSpaces());
        // 返回空字符串, 过滤
        if (StringUtils.isNotBlank(ddr_new.getNextToken())) {
            _getSpaces(accessToken, unionId, maxResults, ddr_new.getNextToken(), dataList);
        }
        return dataList;
    }

    /**
     * 获取文件或文件夹列表
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-the-file-list-storage
     */

    @Override
    public List<Map> getDentries(String accessToken, String unionId, String spaceId, String parentId, Map extInfo) {

        return _getDentries(accessToken, unionId, spaceId, parentId, maxResults, null, extInfo, new ArrayList<>());
    }

    /// 递归文件/文件夹列表
    private List<Map> _getDentries(String accessToken, String unionId, String spaceId, String parentId, int maxResults, String nextToken, Map extInfo, List<Map> dataList) {

        Map param = UtilMap.map("unionId, parentId, maxResults, nextToken", unionId, parentId, maxResults, nextToken);
        UtilMap.putAll(param, extInfo);
        DDR_New ddr_new = DDR_New.doGet("https://api.dingtalk.com//v1.0/storage/spaces/" + spaceId + "/dentries", DDConf.initTokenHeader(accessToken), param);
        dataList.addAll(ddr_new.getDentries());
        // 返回空字符串, 过滤
        if (StringUtils.isNotBlank(ddr_new.getNextToken())) {
            _getDentries(accessToken, unionId, spaceId, parentId, maxResults, ddr_new.getNextToken(), extInfo, dataList);
        }
        return dataList;
    }

    /**
     * 添加文件夹
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/add-folder
     */
    @Override
    public Map addFolders(String accessToken, String unionId, String spaceId, String parentId, String name, Map option) {

        // ppExt: / \ * < > | "  [参考: 常用Unicode字符对照表]
        name = name.replaceAll("\\u002F", "");
        name = name.replaceAll("\\u005C", "");
        name = name.replaceAll("\\u002A", "");
        name = name.replaceAll("\\u003C", "");
        name = name.replaceAll("\\u003E", "");
        name = name.replaceAll("\\u007C", "");
        name = name.replaceAll("\\u0022", "");
        if (name.endsWith(".")) {
            name = name.substring(0, name.length() - 1);
        }
        Map param = UtilMap.map("unionId", unionId);
        Map body = UtilMap.map("name", name);
        if (ObjectUtil.isNotNull(option)) {
            body.put("option", option);
        }
        DDR_New ddr_new = DDR_New.doPost("https://api.dingtalk.com//v1.0/storage/spaces/" + spaceId + "/dentries/" + parentId + "/folders", DDConf.initTokenHeader(accessToken), param, body);
        return ddr_new.getDentry();
    }

    ///////////////////////// OA审批附件 /////////////////////////

    /**
     * 获取审批钉盘空间信息
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtains-the-information-about-approval-nail-disk
     */
    @Override
    public String getSpacesInfos(String access_token, String userId, String agentId) {
        Map header = DDConf.initTokenHeader(access_token);
        Map body = UtilMap.map("userId, agentId", userId, agentId);
        DDR_New ddr = DDR_New.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/spaces/infos/query", header, null, body);
        return String.valueOf(((Map) ddr.getResult()).get("spaceId"));
    }

    /**
     * 添加权限
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/add-storage-permissions
     */
    @Override
    public boolean addSpacePermissions(String access_token, String spaceId, String dentryId, String unionId, String roleId, List<Map> members, Map option) {
        String url = "https://api.dingtalk.com/v1.0/storage/spaces/" + spaceId + "/dentries/" + dentryId + "/permissions";
        Map header = DDConf.initTokenHeader(access_token);
        Map param = UtilMap.map("unionId", unionId);
        Map body = UtilMap.map("roleId, members, option", roleId, members, option);
        if (ObjectUtil.isNotNull(option)) {
            body.putAll(option);
        }
        return DDR_New.doPost(url, header, param, body).isSuccess();
    }

    ///////////////////////// 通用上传逻辑 /////////////////////////

    /**
     * 获取文件上传信息
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-storage-upload-information
     */
    @Override
    public DDR_New getUploadInfos(String access_token, String spaceId, String unionId, Map option) {
        String path = "https://api.dingtalk.com/v1.0/storage/spaces/" + spaceId + "/files/uploadInfos/query";
        Map header = DDConf.initTokenHeader(access_token);
        Map param = UtilMap.map("unionId", unionId);
        Map body = UtilMap.map("protocol, multipart", "HEADER_SIGNATURE", true);
        if (ObjectUtil.isNotNull(option)) {
            body.putAll(option);
        }
        return DDR_New.doPost(path, header, param, body);
    }

    /**
     * 文件上传 [官方]
     *
     * @implNote 从[获取文件上传信息]接口返回信息中拿到resourceUrls和headers
     */
    @Override
    @SneakyThrows
    public boolean uploadFiles(String resourceUrl, Map<String, String> headerSignatureInfo, String pathFile) {
        Map<String, String> headers = headerSignatureInfo;
        URL url = new URL(resourceUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                connection.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        connection.setDoOutput(true);
        connection.setRequestMethod("PUT");
        connection.setUseCaches(false);
        connection.setReadTimeout(10000);
        connection.setConnectTimeout(10000);
        connection.connect();
        OutputStream out = connection.getOutputStream();
        InputStream is = new FileInputStream(pathFile);
        byte[] b = new byte[1024];
        int temp;
        while ((temp = is.read(b)) != -1) {
            out.write(b, 0, temp);
        }
        out.flush();
        out.close();
        int responseCode = connection.getResponseCode();
        connection.disconnect();
        return responseCode == 200;
    }

    /**
     * 提交文件
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/submit-documents
     */
    @Override
    public Map commitFiles(String access_token, String spaceId, String unionId, String uploadKey, String name, String parentId, Map option) {
        String url = "https://api.dingtalk.com/v1.0/storage/spaces/" + spaceId + "/files/commit";
        Map header = DDConf.initTokenHeader(access_token);
        Map param = UtilMap.map("unionId", unionId);
        Map body = UtilMap.map("uploadKey, name, parentId", uploadKey, name, parentId);
        if (ObjectUtil.isNotNull(option)) {
            body.putAll(option);
        }
        DDR_New ddr = DDR_New.doPost(url, header, param, body);
        return ddr.getDentry();
    }
}
