package com.gxwebsoft.ai.util;

import com.aliyun.bailian20231229.Client;
import com.aliyun.bailian20231229.models.*;
import com.aliyun.teautil.models.RuntimeOptions;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.hutool.core.util.StrUtil;

import java.util.Map;

import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * 云数据中心工具类
 * @author yc
 *
 */
public class AiCloudDataCenterUtil {

    /**
     * 类目列表
     *
     * @param client      客户端对象
     * @param workspaceId 业务空间ID
     * @param categoryId  父类目ID
     * @return 阿里云百炼服务的响应
     */
    public static ListCategoryResponse listCategory(Client client, String workspaceId, String parentCategoryId) throws Exception {
        ListCategoryRequest listCategoryRequest = new ListCategoryRequest();
        listCategoryRequest.setCategoryType("UNSTRUCTURED");
        listCategoryRequest.setParentCategoryId(parentCategoryId);
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.listCategoryWithOptions(workspaceId, listCategoryRequest, headers, runtime);
    }

    /**
     * 删除类目
     *
     * @param client      客户端对象
     * @param workspaceId 业务空间ID
     * @param categoryId  类目ID
     * @return 阿里云百炼服务的响应
     */
    public static DeleteCategoryResponse deleteCategory(Client client, String workspaceId, String categoryId) throws Exception {
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.deleteCategoryWithOptions(categoryId, workspaceId, headers, runtime);
    }

    /**
     * 添加类目
     *
     * @param client          客户端对象
     * @param workspaceId     业务空间ID
     * @param addCategoryRequest 添加类目请求对象
     * @return 阿里云百炼服务的响应
     */
    public static AddCategoryResponse addCategory(Client client, String workspaceId, String parentCategoryId, String categoryName) throws Exception {
    	AddCategoryRequest addCategoryRequest = new AddCategoryRequest();
    	addCategoryRequest.setCategoryType("UNSTRUCTURED");
    	addCategoryRequest.setParentCategoryId(parentCategoryId);
    	addCategoryRequest.setCategoryName(categoryName);
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.addCategoryWithOptions(workspaceId, addCategoryRequest, headers, runtime);
    }

    /**
     * 文件列表
     *
     * @param client      客户端对象
     * @param workspaceId 业务空间ID
     * @return 阿里云百炼服务的响应
     */
    public static ListFileResponse listFile(Client client, String workspaceId, String categoryId, String fileName) throws Exception {
        ListFileRequest listFileRequest = new ListFileRequest();
        listFileRequest.setCategoryId(categoryId);
        if(StrUtil.isNotBlank(fileName)) {
        	listFileRequest.setFileName(fileName);
        }
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.listFileWithOptions(workspaceId, listFileRequest, headers, runtime);
    }

    /**
     * 添加文件
     *
     * @param client          客户端对象
     * @param workspaceId     业务空间ID
     * @param addFileRequest  添加文件请求对象
     * @return 阿里云百炼服务的响应
     */
    public static AddFileResponse addFile(Client client, String workspaceId, String categoryId, String leaseId) throws Exception {
    	AddFileRequest addFileRequest = new AddFileRequest();
    	addFileRequest.setCategoryId(categoryId);
    	addFileRequest.setLeaseId(leaseId);
    	addFileRequest.setParser("DASHSCOPE_DOCMIND");
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.addFileWithOptions(workspaceId, addFileRequest, headers, runtime);
    }

//    /**
//     * 从授权OSS添加文件（弃用）
//     *
//     * @param client                          客户端对象
//     * @param workspaceId                     业务空间ID
//     * @param addFilesFromAuthorizedOssRequest 从授权OSS添加文件请求对象
//     * @return 阿里云百炼服务的响应
//     */
//    public static AddFilesFromAuthorizedOssResponse addFilesFromAuthorizedOss(Client client, String workspaceId, AddFilesFromAuthorizedOssRequest addFilesFromAuthorizedOssRequest) throws Exception {
//        RuntimeOptions runtime = new RuntimeOptions();
//        Map<String, String> headers = new HashMap<>();
//        return client.addFilesFromAuthorizedOssWithOptions(workspaceId, addFilesFromAuthorizedOssRequest, headers, runtime);
//    }

    /**
     * 申请文件上传租约
     *
     * @param client                      客户端对象
     * @param workspaceId                 业务空间ID
     * @param categoryId                  类目ID
     * @param applyFileUploadLeaseRequest 申请文件上传租约请求对象
     * @return 阿里云百炼服务的响应
     */
    public static ApplyFileUploadLeaseResponse applyFileUploadLease(Client client, String workspaceId, String categoryId, String fileName, String md5, String size) throws Exception {
    	ApplyFileUploadLeaseRequest applyFileUploadLeaseRequest = new ApplyFileUploadLeaseRequest();
    	applyFileUploadLeaseRequest.setFileName(fileName);
    	applyFileUploadLeaseRequest.setMd5(md5);
    	applyFileUploadLeaseRequest.setSizeInBytes(size);
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.applyFileUploadLeaseWithOptions(categoryId, workspaceId, applyFileUploadLeaseRequest, headers, runtime);
    }

    /**
     * 删除文件
     *
     * @param client      客户端对象
     * @param workspaceId 业务空间ID
     * @param fileId      文件ID
     * @return 阿里云百炼服务的响应
     */
    public static DeleteFileResponse deleteFile(Client client, String workspaceId, String fileId) throws Exception {
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.deleteFileWithOptions(fileId, workspaceId, headers, runtime);
    }

    /**
     * 描述文件
     *
     * @param client      客户端对象
     * @param workspaceId 业务空间ID
     * @param fileId      文件ID
     * @return 阿里云百炼服务的响应
     */
    public static DescribeFileResponse describeFile(Client client, String workspaceId, String fileId) throws Exception {
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.describeFileWithOptions(workspaceId, fileId, headers, runtime);
    }

    /**
     * 更新文件标签
     *
     * @param client             客户端对象
     * @param workspaceId        业务空间ID
     * @param fileId             文件ID
     * @param updateFileTagRequest 更新文件标签请求对象
     * @return 阿里云百炼服务的响应
     */
    public static UpdateFileTagResponse updateFileTag(Client client, String workspaceId, String fileId, List<String> tags) throws Exception {
    	UpdateFileTagRequest updateFileTagRequest = new UpdateFileTagRequest();
    	updateFileTagRequest.setTags(tags);
        RuntimeOptions runtime = new RuntimeOptions();
        Map<String, String> headers = new HashMap<>();
        return client.updateFileTagWithOptions(workspaceId, fileId, updateFileTagRequest, headers, runtime);
    }

//    /**
//     * 获取解析设置
//     *
//     * @param client                  客户端对象
//     * @param workspaceId             业务空间ID
//     * @param getParseSettingsRequest 获取解析设置请求对象
//     * @return 阿里云百炼服务的响应
//     */
//    public static GetParseSettingsResponse getParseSettings(Client client, String workspaceId, GetParseSettingsRequest getParseSettingsRequest) throws Exception {
//        RuntimeOptions runtime = new RuntimeOptions();
//        Map<String, String> headers = new HashMap<>();
//        return client.getParseSettingsWithOptions(workspaceId, getParseSettingsRequest, headers, runtime);
//    }
//
//    /**
//     * 获取可用解析器类型
//     *
//     * @param client                       客户端对象
//     * @param workspaceId                  业务空间ID
//     * @param getAvailableParserTypesRequest 获取可用解析器类型请求对象
//     * @return 阿里云百炼服务的响应
//     */
//    public static GetAvailableParserTypesResponse getAvailableParserTypes(Client client, String workspaceId, GetAvailableParserTypesRequest getAvailableParserTypesRequest) throws Exception {
//        RuntimeOptions runtime = new RuntimeOptions();
//        Map<String, String> headers = new HashMap<>();
//        return client.getAvailableParserTypesWithOptions(workspaceId, getAvailableParserTypesRequest, headers, runtime);
//    }
//
//    /**
//     * 更改解析设置
//     *
//     * @param client                   客户端对象
//     * @param workspaceId              业务空间ID
//     * @param changeParseSettingRequest 更改解析设置请求对象
//     * @return 阿里云百炼服务的响应
//     */
//    public static ChangeParseSettingResponse changeParseSetting(Client client, String workspaceId, ChangeParseSettingRequest changeParseSettingRequest) throws Exception {
//        RuntimeOptions runtime = new RuntimeOptions();
//        Map<String, String> headers = new HashMap<>();
//        return client.changeParseSettingWithOptions(workspaceId, changeParseSettingRequest, headers, runtime);
//    }
    

    
    /**
     * 上传文件
     *
     * @param client          客户端对象
     * @param workspaceId     业务空间ID
     * @param addFileRequest  添加文件请求对象
     * @return 阿里云百炼服务的响应
     */
    public static AddFileResponse uploadFile(Client client, String workspaceId, String categoryId, MultipartFile file) throws Exception {
        // 准备文档信息
        String fileName = file.getOriginalFilename();
        String fileMd5 = calculateMD5(file.getInputStream());
        String fileSize = String.valueOf(file.getSize());
    	
    	ApplyFileUploadLeaseResponse applyFileUploadLeaseResponse = applyFileUploadLease(client, workspaceId, categoryId, fileName, fileMd5, fileSize);
    	
        String leaseId = applyFileUploadLeaseResponse.getBody().getData().getFileUploadLeaseId();
        String uploadUrl = applyFileUploadLeaseResponse.getBody().getData().getParam().getUrl();
        
        // 上传文件
        ObjectMapper mapper = new ObjectMapper();
        Map<String, String> headers = mapper.readValue(mapper.writeValueAsString(applyFileUploadLeaseResponse.getBody().getData().getParam().getHeaders()), Map.class);
        uploadFile(uploadUrl, headers, file);
        
        AddFileResponse addFileResponse = addFile(client, workspaceId, categoryId, leaseId);
        
        String fileId = addFileResponse.getBody().getData().getFileId();
        waitForFileParsing(client, workspaceId, fileId);
        
        // fileId的UUID部分做为标签更新 file_df12ed21b7384353bd75868444c516ae_10377381  -> df12ed21b7384353bd75868444c516ae
        String tag = StrUtil.subBetween(fileId, "_", "_").substring(0, 32);
        updateFileTag(client, workspaceId, fileId, Arrays.asList(tag));
        
        return addFileResponse;
    }
    
	private static void uploadFile(String preSignedUrl, Map<String, String> headers, MultipartFile file) throws Exception {
		HttpURLConnection conn = (HttpURLConnection) new URL(preSignedUrl).openConnection();
		conn.setRequestMethod("PUT");
		conn.setDoOutput(true);
		conn.setRequestProperty("X-bailian-extra", headers.get("X-bailian-extra"));
		conn.setRequestProperty("Content-Type", headers.get("Content-Type"));

		try (InputStream inputStream = file.getInputStream()) {
			byte[] buffer = new byte[4096];
			int bytesRead;
			while ((bytesRead = inputStream.read(buffer)) != -1) {
				conn.getOutputStream().write(buffer, 0, bytesRead);
			}
		}

		if (conn.getResponseCode() != 200) {
			throw new RuntimeException("上传失败: " + conn.getResponseCode());
		}
	}
	
	private static String calculateMD5(InputStream inputStream) throws Exception {
	    MessageDigest md = MessageDigest.getInstance("MD5");
	    byte[] buffer = new byte[4096];
	    int bytesRead;
	    while ((bytesRead = inputStream.read(buffer)) != -1) {
	        md.update(buffer, 0, bytesRead);
	    }
	    StringBuilder sb = new StringBuilder();
	    for (byte b : md.digest()) {
	        sb.append(String.format("%02x", b & 0xff));
	    }
	    return sb.toString();
	}
	
	private static void waitForFileParsing(Client client, String workspaceId, String fileId) throws Exception {
	    long timeout = 30 * 60 * 1000; // 30分钟超时
	    long startTime = System.currentTimeMillis();
	    while (true) {
	        // 检查超时
	        if (System.currentTimeMillis() - startTime > timeout) {
	            throw new RuntimeException("文档解析超时");
	        }
	        DescribeFileResponse response = describeFile(client, workspaceId, fileId);
	        String status = response.getBody().getData().getStatus();
	        if ("PARSE_SUCCESS".equals(status)) {
	            break;
	        } else if ("PARSE_FAILED".equals(status)) {
	            throw new RuntimeException("文档解析失败");
	        }
	        Thread.sleep(3000);
	    }
	}
}