package com.example.backend.service;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkdrive_1_0.models.ListSpacesHeaders;
import com.aliyun.dingtalkdrive_1_0.models.ListSpacesRequest;
import com.aliyun.dingtalkstorage_1_0.models.GetFileDownloadInfoResponse;
import com.aliyun.dingtalkstorage_2_0.models.CommitFileResponse;
import com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoResponse;
import com.aliyun.dingtalkstorage_2_0.models.SearchDentriesResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.example.backend.dto.CommitFileResult;
import com.example.backend.exception.BizException;
import jakarta.servlet.http.HttpServletResponse;
import okhttp3.*;
import okio.BufferedSink;
import okio.Okio;
import okio.Sink;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

/**
 * /**
 *
 * @ClassName 空间管理
 * @Author QY
 * @Date 2025/8/5 11:23
 * @Version 1.0
 **/
@Component
public class WorkService {

  @Autowired
  BlockingQueue<Long> blockingQueue;

  /**
   * 获取空间信息
   *
   * @param unionId
   * @return
   */
  public String getWorkspace(String unionId, String accessToken, Config config) {
    try {
      com.aliyun.dingtalkdrive_1_0.Client client = new com.aliyun.dingtalkdrive_1_0.Client(config);
      ListSpacesHeaders listSpacesHeaders = new ListSpacesHeaders();
      listSpacesHeaders.xAcsDingtalkAccessToken = accessToken;
      ListSpacesRequest listSpacesRequest = new ListSpacesRequest()
        .setUnionId(unionId)
        .setSpaceType("org")
        .setMaxResults(50);
      return client.listSpacesWithOptions(listSpacesRequest, listSpacesHeaders, new RuntimeOptions()).getBody().getSpaces().get(1).getSpaceId();
    } catch (Exception err) {
      throw new BizException("获取知识库信息失败: " + err.getMessage());
    }
  }

  /**
   * 搜索文件夹
   *
   * @param unionId
   * @return
   */
  public String getSearch(String unionId, String accessToken, Config config) {
    try {
      com.aliyun.dingtalkstorage_2_0.Client client = new com.aliyun.dingtalkstorage_2_0.Client(config);
      com.aliyun.dingtalkstorage_2_0.models.SearchDentriesHeaders searchDentriesHeaders = new com.aliyun.dingtalkstorage_2_0.models.SearchDentriesHeaders();
      searchDentriesHeaders.xAcsDingtalkAccessToken = accessToken;
      com.aliyun.dingtalkstorage_2_0.models.SearchDentriesRequest searchDentriesRequest = new com.aliyun.dingtalkstorage_2_0.models.SearchDentriesRequest()
        .setOperatorId(unionId)
        .setKeyword("测试文件夹");
      SearchDentriesResponse searchDentriesResponse = client.searchDentriesWithOptions(searchDentriesRequest, searchDentriesHeaders, new com.aliyun.teautil.models.RuntimeOptions());
      return searchDentriesResponse.getBody().getItems().get(0).getDentryUuid();
    } catch (Exception err) {
      throw new RuntimeException(err);
    }
  }

  /**
   * OSS方式上传
   *
   * @param resourceUrl
   * @param headers
   * @param file
   * @return
   */
  public String uploadToResource(String resourceUrl, Map<String, String> headers, MultipartFile file) {
    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();
      try (OutputStream out = connection.getOutputStream(); InputStream is = file.getInputStream()) {
        byte[] b = new byte[1024];
        int temp;
        while ((temp = is.read(b)) != -1) {
          out.write(b, 0, temp);
        }
        out.flush();
      }
      int responseCode = connection.getResponseCode();
      connection.disconnect();
      if (responseCode == 200) {
        return "上传成功";
      } else {
        return "上传失败，响应码：" + responseCode;
      }
    } catch (Exception e) {
      throw new BizException("上传异常: " + e.getMessage());
    }
  }

  /**
   * 获取文件上传信息
   *
   * @param unionId
   * @param getSearchId
   * @param dentryName
   * @param size
   * @return
   */
  public JSONObject getUploadInfo(String unionId, String getSearchId, String dentryName, Long size, String accessToken, Config config) {
    try {
      com.aliyun.dingtalkstorage_2_0.Client client = new com.aliyun.dingtalkstorage_2_0.Client(config);
      com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoHeaders getFileUploadInfoHeaders = new com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoHeaders();
      getFileUploadInfoHeaders.xAcsDingtalkAccessToken = accessToken;
      com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoRequest.GetFileUploadInfoRequestOptionPreCheckParam optionPreCheckParam = new com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoRequest.GetFileUploadInfoRequestOptionPreCheckParam()
        .setSize(size)
        .setName(dentryName);
      com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoRequest.GetFileUploadInfoRequestOption option = new com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoRequest.GetFileUploadInfoRequestOption()
        .setStorageDriver("DINGTALK");
      com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoRequest getFileUploadInfoRequest = new com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoRequest()
        .setUnionId(unionId)
        .setProtocol("HEADER_SIGNATURE")
        .setOption(option);
      GetFileUploadInfoResponse getFileUploadInfoResponse = client.getFileUploadInfoWithOptions(getSearchId, getFileUploadInfoRequest, getFileUploadInfoHeaders, new com.aliyun.teautil.models.RuntimeOptions());
      JSONObject json = new JSONObject();
      json.put("resourceUrls", getFileUploadInfoResponse.getBody().getHeaderSignatureInfo().getResourceUrls().get(0));
      json.put("headers", getFileUploadInfoResponse.getBody().getHeaderSignatureInfo().getHeaders());
      json.put("uploadKey", getFileUploadInfoResponse.getBody().getUploadKey());
      return json;

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 获取地址
   *
   * @param size
   * @param unionId
   * @param uploadKey
   * @param dentryName
   * @param getSearchId
   * @param accessToken
   * @param config
   * @return
   */
  public CommitFileResult getUrl(Long size, String unionId, String uploadKey, String dentryName, String getSearchId, String accessToken, Config config) {
    try {
      com.aliyun.dingtalkstorage_2_0.Client client = new com.aliyun.dingtalkstorage_2_0.Client(config);
      com.aliyun.dingtalkstorage_2_0.models.CommitFileHeaders commitFileHeaders = new com.aliyun.dingtalkstorage_2_0.models.CommitFileHeaders();
      commitFileHeaders.xAcsDingtalkAccessToken = accessToken;
      com.aliyun.dingtalkstorage_2_0.models.CommitFileRequest.CommitFileRequestOptionAppProperties optionAppProperties0 = new com.aliyun.dingtalkstorage_2_0.models.CommitFileRequest.CommitFileRequestOptionAppProperties()
        .setName("property_name")
        .setValue("property_value")
        .setVisibility("PRIVATE");
      com.aliyun.dingtalkstorage_2_0.models.CommitFileRequest.CommitFileRequestOption option = new com.aliyun.dingtalkstorage_2_0.models.CommitFileRequest.CommitFileRequestOption()
        .setSize(size)
        .setConflictStrategy("OVERWRITE")
        .setAppProperties(Arrays.asList(
          optionAppProperties0
        ))
        .setConvertToOnlineDoc(false);
      com.aliyun.dingtalkstorage_2_0.models.CommitFileRequest commitFileRequest = new com.aliyun.dingtalkstorage_2_0.models.CommitFileRequest()
        .setUnionId(unionId)
        .setUploadKey(uploadKey)
        .setName(dentryName)
        .setOption(option);
      CommitFileResponse commitFileResponse = client.commitFileWithOptions(getSearchId, commitFileRequest, commitFileHeaders, new com.aliyun.teautil.models.RuntimeOptions());
      String docUrl = "https://alidocs.dingtalk.com/i/nodes/" + commitFileResponse.getBody().getDentry().getUuid();
      return new CommitFileResult(true, docUrl);
    } catch (Exception err) {
      throw new BizException("提交文件失败: " + err.getMessage());
    }
  }

  /**
   * 获取文件下载信息
   *
   * @param unionId
   * @param spaceId
   * @param fildId
   * @return
   */
  public GetFileDownloadInfoResponse getFileDownInfo(String unionId, String spaceId, String fildId, String accessToken, Config config) {
    try {
      com.aliyun.dingtalkstorage_1_0.Client client = new com.aliyun.dingtalkstorage_1_0.Client(config);
      com.aliyun.dingtalkstorage_1_0.models.GetFileDownloadInfoHeaders getFileDownloadInfoHeaders = new com.aliyun.dingtalkstorage_1_0.models.GetFileDownloadInfoHeaders();
      getFileDownloadInfoHeaders.xAcsDingtalkAccessToken = accessToken;
      com.aliyun.dingtalkstorage_1_0.models.GetFileDownloadInfoRequest getFileDownloadInfoRequest = new com.aliyun.dingtalkstorage_1_0.models.GetFileDownloadInfoRequest()
        .setUnionId(unionId);
      return client.getFileDownloadInfoWithOptions(spaceId, fildId, getFileDownloadInfoRequest, getFileDownloadInfoHeaders, new com.aliyun.teautil.models.RuntimeOptions());
    } catch (TeaException e) {
      System.out.println("获取失败: "+ e.getMessage());
      throw new RuntimeException(e);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public String DownLoadFile(GetFileDownloadInfoResponse getDentryResponse, String fileName) {
    try {
      // 调用获取下载信息接口获取的internalResourceUrls。
      String url = getDentryResponse.getBody().getHeaderSignatureInfo().getResourceUrls().get(0);
      //调用下载信息接口获取的headers。
      Map<String, String> headers = getDentryResponse.getBody().getHeaderSignatureInfo().getHeaders();
      // 下载到本地到文件路径
      String path = System.getProperties().getProperty("user.dir");
      String filePath = path + "/" + fileName;
      System.out.println("filepath download:" + filePath);
      downloadFiles(url, headers, filePath);
      return "ok";
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 下载文件
   *
   * @param url
   * @param header
   * @param filepath
   */
  public void downloadFiles(String url, Map<String, String> header, String filepath) {
    try {
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
      .url(url)
      .headers(Headers.of(header))
      .build();
    client.newCall(request).enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        e.printStackTrace();
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        Sink sink = null;
        BufferedSink bufferedSink = null;
        try {
          File dest = new File(filepath);
          sink = Okio.sink(dest);
          bufferedSink = Okio.buffer(sink);
          long size = bufferedSink.writeAll(response.body().source());
          System.out.println("responseWriter file exists");
          if (size > 0) {
            blockingQueue.offer(size);
          }
        } catch (Exception e) {
          e.printStackTrace();
        } finally {
          if (bufferedSink != null) {
            bufferedSink.close();
          }
          if (sink != null) {
            sink.close();
          }
        }
      }
    });
  }

  /**
   * 文件下载给浏览器
   *
   * @param response response
   * @param filePath 文件路径
   * @param fileName 文件名
   * @throws IOException
   */
  public void responseWriter(HttpServletResponse response, String filePath, String fileName) throws IOException {

    File file = new File(filePath);
    if (!file.exists()) {
      System.out.println("responseWriter file exists");
    }
    InputStream in = new FileInputStream(filePath);
    int len = 0;
    byte[] buffer = new byte[1024];
    OutputStream out = response.getOutputStream();
    while ((len = in.read(buffer)) > 0) {
      out.write(buffer, 0, len);
    }
    in.close();
  }
}
