package com.malk.lianxiang.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.malk.lianxiang.service.LianxiangService;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.common.McR;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.aliwork.YDClient;
import com.malk.service.dingtalk.DDClient;
import com.malk.utils.UtilHttp;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

@Slf4j
@Service
public class LianxiangServiceImpl implements LianxiangService {

    @Autowired
    private YDClient ydClient;

    @Autowired
    private YDConf ydConf;

    @Autowired
    private DDClient ddClient;

    @Autowired
    private DDConf ddConf;

    @Value(value = "${dingtalk.unionId}")
    private String unionId;

    @Value(value = "${dingtalk.spaceId}")
    private String spaceId;

    @Value(value = "${saveFile.path}")
    private String saveFilePath;

    @Value(value = "${dingtalk.partnersDentryId}")
    private String partnersDentryId;

    @Value(value = "${dingtalk.unrestrictedDonationDentryId}")
    private String unrestrictedDonationDentryId;

    //key:项目文档类型  valueIndex:0：附件字段，1：标题字段, 2：项目名称字段
    private static final Map<String,List<String>> DOCUMENT_TYPE = new HashMap<>();
    
    static {
        DOCUMENT_TYPE.put("立项文件", Arrays.asList("attachmentField_m8pm41hk","textField_m8pm41gx"));

        DOCUMENT_TYPE.put("项目产出成果文件", Arrays.asList("attachmentField_m8s488ko","textField_m9ko40z1","selectField_m8s3yt3o"));
        DOCUMENT_TYPE.put("三方比价单文件", Arrays.asList("attachmentField_m8s4ejmk","textField_m9ko40z1","textField_m8s518bj"));
        DOCUMENT_TYPE.put("合同文件", Arrays.asList("attachmentField_m9ko7k03","textField_m8s4w6yb","textField_m988ws0i"));
        DOCUMENT_TYPE.put("捐赠发票文件", Arrays.asList("attachmentField_m9c3dzgx","textField_m9ko40z1","textField_m9kqf27r"));
        DOCUMENT_TYPE.put("用印申报文件", Arrays.asList("attachmentField_m9koc6zh","textField_m9ko40z1","textField_m9kqxytx"));

        DOCUMENT_TYPE.put("资助人费用登记文件", Arrays.asList("attachmentField_m9kszuos","textField_m9ko40z1"));
        DOCUMENT_TYPE.put("合作伙伴文件", Arrays.asList("attachmentField_m8plqur3","textField_m9b1hlci"));
    }

    //钉盘提交文件文件名称冲突策略
    private static final Map<String,String> CONFLICT_STRATEGY = new HashMap<>();

    static {
        CONFLICT_STRATEGY.put("自动重命名","AUTO_RENAME");
        CONFLICT_STRATEGY.put("覆盖","OVERWRITE");
        CONFLICT_STRATEGY.put("返回已存在文件","RETURN_DENTRY_IF_EXISTS");
        CONFLICT_STRATEGY.put("文件已存在时报错","RETURN_ERROR_IF_EXISTS");
    }

    @Override
    public McR projectInitiation(String formInstId) {
        Map formData = ydClient.queryData(YDParam.builder()
                .formInstId(formInstId)
                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

        //1.创建项目名称文件夹
        String projectName = formData.get("textField_m8pm41gx").toString();
        Map dentry = createFolder(spaceId, "0", projectName, unionId);

        String folderId = dentry.get("id").toString();

        //2。创建项目各文档文件夹
        String projectInitiationFolderUuid = "";
        for (String documentType : DOCUMENT_TYPE.keySet()) {
            if (documentType.equals("合作伙伴文件") || documentType.equals("资助人费用登记文件")){
                continue;
            }
            Map dentry2 = createFolder(spaceId, folderId, documentType, unionId);
            if(documentType.equals("立项文件")){
                projectInitiationFolderUuid = dentry2.get("uuid").toString();
            }
        }

        if (Objects.nonNull(formData.get("attachmentField_m8pm41hk"))){
            List<Map> fileList = (List<Map>) JSONArray.parse(String.valueOf(formData.get("attachmentField_m8pm41hk")));
            for (Map file : fileList) {
                String ydDownloadUrl = file.get("downloadUrl").toString();
                String fileName = file.get("name").toString();

                //将downloadurl下载到本地
                try {
                    downloadYdFile(ydDownloadUrl, saveFilePath + fileName);
                    System.out.println("文件下载成功！");
                } catch (IOException e) {
                    e.printStackTrace();
                }

                //上传至钉盘-项目文件夹-立项文件
                uploadToDingTalk(saveFilePath + fileName ,projectInitiationFolderUuid,CONFLICT_STRATEGY.get("覆盖"));
            }
        }
        return McR.success();
    }

    @Override
    public McR uploadProjectFiles(String formInstId, String type) {
        List<String> fieldList = DOCUMENT_TYPE.get(type);

        if (Objects.nonNull(fieldList) && !fieldList.isEmpty()){
            Map formData = ydClient.queryData(YDParam.builder()
                    .formInstId(formInstId)
                    .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

            String fileField = fieldList.get(0);//附件字段id
            String title = formData.get(fieldList.get(1)).toString();//数据标题

            if (Objects.nonNull(formData.get(fileField))){
                String uploadFolderUuid = "";

                List<Map> fileList = (List<Map>) JSONArray.parse(String.valueOf(formData.get(fileField)));
                for (Map file : fileList) {
                    String ydDownloadUrl = file.get("downloadUrl").toString();
                    String fileName = file.get("name").toString();

                    //将downloadurl下载到本地
                    try {
                        downloadYdFile(ydDownloadUrl, saveFilePath + fileName);
                        System.out.println("文件下载成功！");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    if (type.equals("合作伙伴文件")){
                        if (Strings.isBlank(uploadFolderUuid)){
                            //查询标题文件夹是否存在
                            Map titleFolder = getDentryList(spaceId, partnersDentryId, unionId, "").stream()
                                    .filter(map -> map.get("name").toString().equals(title) && map.get("type").toString().equals("FOLDER"))
                                    .findFirst()
                                    .orElse(null);

                            if (Objects.nonNull(titleFolder)){
                                uploadFolderUuid = titleFolder.get("uuid").toString();
                            }else {
                                //创建该数据标题文件夹
                                Map dentry = createFolder(spaceId, partnersDentryId, title, unionId);

                                uploadFolderUuid = dentry.get("uuid").toString();
                            }
                        }

                        //上传至钉盘-宜搭文件库-合作伙伴文件夹-标题文件夹
                        uploadToDingTalk(saveFilePath + fileName ,uploadFolderUuid,CONFLICT_STRATEGY.get("覆盖"));
                    }else if (type.equals("资助人费用登记文件")){
                        if (Strings.isBlank(uploadFolderUuid)){
                            //查询标题文件夹是否存在
                            Map titleFolder = getDentryList(spaceId, unrestrictedDonationDentryId, unionId, "").stream()
                                    .filter(map -> map.get("name").toString().equals(title) && map.get("type").toString().equals("FOLDER"))
                                    .findFirst()
                                    .orElse(null);

                            if (Objects.nonNull(titleFolder)){
                                uploadFolderUuid = titleFolder.get("uuid").toString();
                            }else {
                                //创建该数据标题文件夹
                                Map dentry = createFolder(spaceId, unrestrictedDonationDentryId, title, unionId);

                                uploadFolderUuid = dentry.get("uuid").toString();
                            }
                        }

                        //上传至钉盘-宜搭文件库-资助人费用登记文件-标题文件夹
                        uploadToDingTalk(saveFilePath + fileName ,uploadFolderUuid,CONFLICT_STRATEGY.get("覆盖"));
                    }else {
                        if (Strings.isBlank(uploadFolderUuid)){
                            //项目文件名称
                            String projectName = formData.get(fieldList.get(2)).toString();

                            //查询项目文件夹信息
                            Map projectFolder = getDentryList(spaceId, "0", unionId, "").stream()
                                    .filter(map -> map.get("name").toString().equals(projectName) && map.get("type").toString().equals("FOLDER"))
                                    .findFirst()
                                    .orElse(null);

                            if (Objects.nonNull(projectFolder)){
                                String projectFolderId = projectFolder.get("id").toString();

                                //查询项目文件夹下对应文档文件夹
                                Map documentFolder = getDentryList(spaceId, projectFolderId, unionId, "").stream()
                                        .filter(map -> map.get("name").toString().equals(type) && map.get("type").toString().equals("FOLDER"))
                                        .findFirst()
                                        .orElse(null);

                                if (Objects.nonNull(documentFolder)){
                                    //文档文件夹id
                                    String documentFolderId = documentFolder.get("id").toString();
                                    //查询标题文件夹是否存在
                                    Map titleFolder = getDentryList(spaceId, documentFolderId, unionId, "").stream()
                                            .filter(map -> map.get("name").toString().equals(title) && map.get("type").toString().equals("FOLDER"))
                                            .findFirst()
                                            .orElse(null);

                                    if (Objects.nonNull(titleFolder)){
                                        uploadFolderUuid = titleFolder.get("uuid").toString();
                                    }else {
                                        //创建该数据标题文件夹
                                        Map dentry = createFolder(spaceId, documentFolderId, title, unionId);

                                        uploadFolderUuid = dentry.get("uuid").toString();
                                    }
                                }else {
                                    return McR.errorUnknown("未找到该文档文件夹！");
                                }
                            }else {
                                return McR.errorParam("未找到该文档所属项目！");
                            }
                        }

                        //上传至钉盘-宜搭文件库-项目文件夹-项目对应文档文件夹-标题文件夹
                        uploadToDingTalk(saveFilePath + fileName ,uploadFolderUuid,CONFLICT_STRATEGY.get("覆盖"));
                    }
                }
            }
        }else {
            return McR.errorParam("未找到该文档类型！");
        }


        return McR.success();
    }

    @Override
    public McR projectInitiationChange(String formInstId) {
        Map formData = ydClient.queryData(YDParam.builder()
                .formInstId(formInstId)
                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

        //1.查询项目名称文件夹
        String projectName = formData.get("textField_m8pm41gx").toString();

        Map projectFolder = getDentryList(spaceId, "0", unionId, "").stream()
                .filter(map -> map.get("name").toString().equals(projectName) && map.get("type").toString().equals("FOLDER"))
                .findFirst()
                .orElse(null);

        if (Objects.nonNull(projectFolder)){
            String projectFolderId = projectFolder.get("id").toString();

            //2.查询立项文件文件夹
            Map projectInitiationFolder = getDentryList(spaceId, projectFolderId, unionId, "").stream()
                    .filter(map -> map.get("name").toString().equals("立项文件") && map.get("type").toString().equals("FOLDER"))
                    .findFirst()
                    .orElse(null);

            if (Objects.nonNull(projectInitiationFolder)){
                String projectInitiationFolderUuid = projectInitiationFolder.get("uuid").toString();

                //3.提交新立项文件
                if (Objects.nonNull(formData.get("attachmentField_m8pm41hk"))){
                    List<Map> fileList = (List<Map>) JSONArray.parse(String.valueOf(formData.get("attachmentField_m8pm41hk")));
                    for (Map file : fileList) {
                        String ydDownloadUrl = file.get("downloadUrl").toString();
                        String fileName = file.get("name").toString();

                        //将downloadurl下载到本地
                        try {
                            downloadYdFile(ydDownloadUrl, saveFilePath + fileName);
                            System.out.println("文件下载成功！");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        //上传至钉盘-项目文件夹-立项文件
                        uploadToDingTalk(saveFilePath + fileName ,projectInitiationFolderUuid,CONFLICT_STRATEGY.get("自动重命名"));
                    }
                }
            }else {
                return McR.errorParam("未找到该立项变更原项目立项文件文件夹");
            }
        }else {
            return McR.errorParam("未找到该立项变更原项目文件夹");
        }

        return McR.success();
    }

    //递归查询所有文件或文件夹列表
    private List<Map> getDentryList(String spaceId, String parentId, String unionId, String nextToken) {
        List<Map> dentryList = new ArrayList<>();

        Map query = new HashMap();
        query.put("parentId",parentId);
        query.put("unionId",unionId);
        query.put("maxResults",50);
        if (Strings.isNotBlank(nextToken)){
            query.put("nextToken",nextToken);
        }

        DDR_New ddrNew = (DDR_New) UtilHttp.doGet("https://api.dingtalk.com/v1.0/storage/spaces/"+spaceId+"/dentries", ddClient.initTokenHeader(), query, DDR_New.class);

        dentryList.addAll(ddrNew.getDentries());

        if (Objects.nonNull(ddrNew.getNextToken())){
            dentryList.addAll(getDentryList(spaceId, parentId, unionId, ddrNew.getNextToken()));
        }

        return dentryList;
    }

    //上传文件至钉盘
    private Map uploadToDingTalk(String filePath,String parentId,String conflictStrategy) {
        //获取当前时间戳
        long beginTimestamp = System.currentTimeMillis();
        System.out.println("开始上传附件：" + DateUtil.format(new Date(beginTimestamp), "yyyy-MM-dd HH:mm:ss"));

        //文件
        File file = new File(filePath);

        //获取文件上传信息
        Map param = new HashMap();
        param.put("unionId",unionId);
        Map body = new HashMap();
        body.put("protocol","HEADER_SIGNATURE");
        body.put("multipart",false);

        DDR_New ddr = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/storage/spaces/" + spaceId + "/files/uploadInfos/query", ddConf.initTokenHeader(ddClient.getAccessToken()), param, body, DDR_New.class);
        String uploadKey = ddr.getUploadKey();
        Map headerSignatureInfo = ddr.getHeaderSignatureInfo();
        Map<String,String> headers = (Map<String,String>) headerSignatureInfo.get("headers");
        List<String> resourceUrls = (List<String>) headerSignatureInfo.get("resourceUrls");
        String resourceUrl = resourceUrls.get(0);

        Map dentry = new HashMap();
        //使用OSS的header加签方式上传文件
        try {
            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(file);
            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();
            if (responseCode == 200) {
                System.out.println("上传成功");
            } else {
                System.out.println("上传失败");
            }
            //提交文件
            Map body2 = new HashMap();
            Map option = new HashMap();
            option.put("conflictStrategy",conflictStrategy);
            body2.put("uploadKey",uploadKey);
            body2.put("name",file.getName());
            body2.put("option",option);
            DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v2.0/storage/spaces/files/"+parentId+"/commit", ddClient.initTokenHeader(), param, body2, DDR_New.class);
            dentry = ddrNew.getDentry();

        }catch (IOException e){
            log.info("上传文件异常:{}",e);
        }

        long endTimestamp = System.currentTimeMillis();
        System.out.println("上传文件结束：" + DateUtil.format(new Date(endTimestamp), "yyyy-MM-dd HH:mm:ss"));
        System.out.println("上传文件耗时：" + (endTimestamp - beginTimestamp)/1000.0 + "s");
        return dentry;
    }

    //下载宜搭附件
    private void downloadYdFile(String fileURL, String savePath) throws IOException {
        //若是宜搭附件url 则需获得附件临时免登地址
        fileURL = ydClient.convertTemporaryUrl(fileURL);

        URL url = new URL(fileURL);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        int responseCode = httpConn.getResponseCode();

        // 检查HTTP响应代码是否为200
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream inputStream = httpConn.getInputStream();
            FileOutputStream outputStream = new FileOutputStream(savePath);

            byte[] buffer = new byte[4096];
            int bytesRead = -1;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.close();
            inputStream.close();
        } else {
            System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
        }
        httpConn.disconnect();
    }

    //创建钉盘文件夹
    private Map createFolder(String spaceId,String parentId,String folderName,String unionId){
        String url = "https://api.dingtalk.com/v1.0/storage/spaces/"+spaceId+"/dentries/"+parentId+"/folders?unionId=iPPoZ001WAYlZxyoU04g2bgiEiE";

        Map query = new HashMap();
        query.put("unionId",unionId);

        Map body = new HashMap();
        body.put("name",folderName);

        DDR_New ddrNew = (DDR_New) UtilHttp.doPost(url, ddClient.initTokenHeader(), query, body, DDR_New.class);

        Map dentry = ddrNew.getDentry();

        return dentry;
    }

    //删除钉盘文件夹或文件
    private void deleteFolder(String spaceId,String dentryId,String unionId){
        String url = "https://api.dingtalk.com/v1.0/storage/spaces/"+spaceId+"/dentries/"+dentryId;

        Map query = new HashMap();
        query.put("unionId",unionId);
        query.put("toRecycleBin",true);

        Map map = (Map) UtilHttp.doDelete(url, ddClient.initTokenHeader(), query, Map.class);
    }


}
