package com.example.backend.service;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.aliyun.dingtalkdrive_1_0.models.GetDownloadInfoResponseBody;
import com.aliyun.dingtalkdrive_1_0.models.ListSpacesHeaders;
import com.aliyun.dingtalkdrive_1_0.models.ListSpacesRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.aliyun.dingtalkstorage_1_0.models.GetDentryResponse;
import com.aliyun.dingtalkstorage_1_0.models.GetFileDownloadInfoResponse;
import com.aliyun.dingtalkstorage_1_0.models.ListDentriesResponse;
import com.aliyun.dingtalkstorage_2_0.models.CommitFileResponse;
import com.aliyun.dingtalkstorage_2_0.models.GetFileUploadInfoResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.models.RuntimeOptions;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import com.example.backend.dto.CommitFileResult;
import com.example.backend.dto.DingtalkUserInfo;
import com.example.backend.exception.BizException;
import com.taobao.api.ApiException;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import okhttp3.*;
import okio.BufferedSink;
import okio.Okio;
import okio.Sink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
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;
import java.util.concurrent.TimeUnit;

/**
 * 钉盘
 */
@Service
public class DingtalkService {
  private static final Logger log = LoggerFactory.getLogger(DingtalkService.class);
  @Value("${dingtalk.clientId}")
  private String clientId;
  @Value("${dingtalk.clientSecret}")
  private String clientSecret;
  @Autowired
  private AccessTokenManager accessTokenManager;


  @Autowired
  private WorkService workService;

  /**
   * 获取token
   *
   * @return
   */
  private String getAccessToken() {
    if (clientId == null || clientSecret == null) {
      throw new BizException("钉钉配置缺失：clientId 或 clientSecret 为空");
    }
    return accessTokenManager.getAccessToken(clientId, clientSecret, (appKey, appSecret) -> {
      try {
        com.aliyun.dingtalkoauth2_1_0.Client client = new com.aliyun.dingtalkoauth2_1_0.Client(getDingTalkConfig());
        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
          .setAppKey(appKey)
          .setAppSecret(appSecret);
        GetAccessTokenResponse resp = client.getAccessToken(getAccessTokenRequest);
        if (resp != null && resp.body != null && resp.body.accessToken != null) {
          return resp.body.accessToken;
        } else {
          throw new BizException("获取钉钉访问令牌失败：响应为空");
        }
      } catch (Exception err) {
        log.error("获取钉钉访问令牌失败", err);
        throw new BizException("获取钉钉访问令牌失败: " + err.getMessage());
      }
    });
  }

  private com.aliyun.teaopenapi.models.Config getDingTalkConfig() {
    com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
    config.protocol = "https";
    config.regionId = "central";
    return config;
  }

  /**
   * 获取登录用户信息
   *
   * @param code
   * @param corpId
   * @return
   */
  public DingtalkUserInfo getUserInfo(String code, String corpId) {
    try {
      log.info("开始获取钉钉用户信息，code={}, corpId={}", code, corpId);
      DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
      OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
      req.setCode(code);
      String accessToken = getAccessToken();
      OapiV2UserGetuserinfoResponse rsp = client.execute(req, accessToken);
      if (!rsp.isSuccess()) {
        log.error("获取钉钉用户信息失败，errcode={}, errmsg={}", rsp.getErrcode(), rsp.getErrmsg());
        throw new BizException(rsp.getErrmsg());
      }
      var result = rsp.getResult();
      DingtalkUserInfo userInfo = new DingtalkUserInfo();
      userInfo.setName(result.getName());
      userInfo.setUserid(result.getUserid());
      userInfo.setUnionid(result.getUnionid());
      userInfo.setSys(result.getSys());
      userInfo.setSysLevel(result.getSysLevel() != null ? result.getSysLevel().intValue() : 0);
      log.info("获取钉钉用户信息成功，userid={}, name={}", userInfo.getUserid(), userInfo.getName());
      return userInfo;
    } catch (ApiException e) {
      log.error("获取钉钉用户信息异常", e);
      throw new BizException("获取用户信息失败: " + e.getMessage());
    }
  }

  /**
   * 上传文件操作
   *
   * @param file
   * @param unionId
   * @param dentryName
   * @param size
   * @return
   */
  public CommitFileResult commitFile(MultipartFile file, String unionId, String dentryName, Long size) {
    log.info("开始上传文件，unionId={}, dentryName={}, size={}", unionId, dentryName, size);
    // 获取空间信息
    //String spaceId = workService.getWorkspace(unionId, getAccessToken(), getDingTalkConfig());
    String getSearchId = workService.getSearch(unionId, getAccessToken(), getDingTalkConfig());
    // 获取文件上传的信息
    JSONObject json = workService.getUploadInfo(unionId, getSearchId, dentryName, size, getAccessToken(), getDingTalkConfig());
    String resourceUrl = json.getString("resourceUrls");
    Map<String, String> headers = json.getJSONObject("headers").toJavaObject(new TypeReference<Map<String, String>>() {
    });
    String uploadKey = json.getString("uploadKey");
    String uploadResult = workService.uploadToResource(resourceUrl, headers, file);
    if (!"上传成功".equals(uploadResult)) {
      log.error("文件上传到资源服务器失败: {}", uploadResult);
      throw new BizException(uploadResult);
    }
    return workService.getUrl(size, unionId, uploadKey, dentryName, getSearchId, getAccessToken(), getDingTalkConfig());
  }

  /**
   * 文件下载
   *
   * @param unionId
   * @return 企业存储文件读权限
   */
  public String DownLoadFile(String unionId) {
    try {
      // 获取空间id
      String spaceId = workService.getWorkspace(unionId, getAccessToken(), getDingTalkConfig());

      com.aliyun.dingtalkstorage_1_0.Client client = new com.aliyun.dingtalkstorage_1_0.Client(getDingTalkConfig());
      com.aliyun.dingtalkstorage_1_0.models.ListDentriesHeaders listDentriesHeaders = new com.aliyun.dingtalkstorage_1_0.models.ListDentriesHeaders();
      listDentriesHeaders.xAcsDingtalkAccessToken = getAccessToken();
      com.aliyun.dingtalkstorage_1_0.models.ListDentriesRequest listDentriesRequest = new com.aliyun.dingtalkstorage_1_0.models.ListDentriesRequest()
        .setParentId("0")
        .setUnionId(unionId);
      // 默认获取的是空间下第一个文件
      String fileId = client.listDentriesWithOptions(spaceId, listDentriesRequest, listDentriesHeaders, new RuntimeOptions()).getBody().getDentries().get(0).id;
      String name = client.listDentriesWithOptions(spaceId, listDentriesRequest, listDentriesHeaders, new RuntimeOptions()).getBody().getDentries().get(0).name;
      // 获取文件下载信息
      GetFileDownloadInfoResponse getDentryResponse = workService.getFileDownInfo(unionId, spaceId, fileId, getAccessToken(), getDingTalkConfig());
      String load = workService.DownLoadFile(getDentryResponse, name);
      return load;
    } catch (Exception e) {
      log.error("获取失败: {}", e.getMessage());
      throw new RuntimeException(e);
    }
  }
}