// uniapp-ZHSQ —— OSS 直传客户端
//
// 用法：
//   import { uploadOSS } from '@/utils/uploadOSS'
//   const { objectKey, url } = await uploadOSS({ filePath: tempFilePath, scene: 'avatar' })
//   // objectKey: OSS 上的相对 key，存数据库
//   // url: 公开访问 URL（如果走签名 URL 显示，前端再单独处理）
//
// 支持的 scene 由服务端 wechatOssSceneCfg 控制，目前：
//   - avatar    用户头像 (jpg/jpeg/png/webp，<=5MB)
//   - merchant  商家入驻资料 (jpg/jpeg/png/webp/pdf，<=10MB)

import { RequsetUrl, aliyunOssUrl } from "@/utils/index.js";

const inferExt = (filePath) => {
  if (!filePath) return "";
  const idx = filePath.lastIndexOf(".");
  if (idx < 0) return "";
  return filePath.substring(idx + 1).toLowerCase();
};

const fetchCredential = (scene, ext, bindId) => {
  return new Promise((resolve, reject) => {
    const data = { scene, ext };
    if (bindId) data.bind_id = bindId; // 客服聊天场景：按会话分目录
    uni.request({
      url: RequsetUrl + "/api/v1/wechat/oss/credential",
      method: "POST",
      header: {
        Authorization: uni.getStorageSync("ctoken") || "",
        "Content-Type": "application/json",
      },
      data,
      success: (res) => {
        if (res.statusCode !== 200) return reject(new Error("获取上传凭证失败:" + res.statusCode));
        const body = res.data || {};
        // 兼容服务端通用响应包装
        const data = body.data || body;
        if (!data || !data.host) return reject(new Error("上传凭证字段缺失"));
        resolve(data);
      },
      fail: (err) => reject(err),
    });
  });
};

const postToOSS = (filePath, cred) => {
  return new Promise((resolve, reject) => {
    uni.uploadFile({
      url: cred.host,
      filePath,
      name: "file", // 必须是 file，OSS PostObject 协议约定
      formData: {
        key: cred.object_key,
        OSSAccessKeyId: cred.access_key_id,
        "x-oss-security-token": cred.security_token,
        policy: cred.policy,
        signature: cred.signature,
        success_action_status: "200",
      },
      success: (res) => {
        // OSS 200 -> 空 body 视为成功
        if (res.statusCode === 200 || res.statusCode === 204) {
          resolve();
        } else {
          reject(new Error("OSS 上传失败:" + res.statusCode + " " + (res.data || "")));
        }
      },
      fail: (err) => reject(err),
    });
  });
};

/**
 * 直传 OSS。
 * @param {Object} opts
 * @param {string} opts.filePath  本地文件临时路径（uni.chooseImage 拿到的 path）
 * @param {string} opts.scene     上传场景：avatar / merchant
 * @param {string} [opts.ext]     扩展名（不含点）；不传则从 filePath 推断
 * @param {boolean} [opts.showLoading=true]
 * @returns {Promise<{ objectKey: string, url: string }>}
 */
export const uploadOSS = async ({ filePath, scene, ext, bindId, showLoading = true }) => {
  if (!filePath) throw new Error("filePath 不能为空");
  if (!scene) throw new Error("scene 不能为空");

  const finalExt = (ext || inferExt(filePath)).toLowerCase();
  if (!finalExt) throw new Error("无法识别文件扩展名");

  if (showLoading) uni.showLoading({ title: "上传中", mask: true });
  try {
    const cred = await fetchCredential(scene, finalExt, bindId);
    await postToOSS(filePath, cred);
    return {
      objectKey: cred.object_key,
      url: aliyunOssUrl + "/" + cred.object_key,
    };
  } finally {
    if (showLoading) uni.hideLoading();
  }
};

/**
 * 兼容旧版 utils/index.js 中 upload(filename, fn) 的回调式 API。
 * 内部走 OSS 直传，回调 res 形状对齐旧版（res.data.path 为以 / 开头的 object key，
 * 调用方 picUrl + res.data.path 可以直接拼成完整 URL）。
 *
 * @param {string} filePath
 * @param {Function} fn  接收 { code, msg, data: { path } }
 * @param {string} [scene='merchant']
 */
export const uploadOSSCompat = (filePath, fn, scene = "merchant") => {
  uploadOSS({ filePath, scene })
    .then(({ objectKey }) => {
      fn && fn({ code: 1, msg: "ok", data: { path: "/" + objectKey } });
    })
    .catch((err) => {
      console.error("uploadOSSCompat 失败:", err);
      uni.showToast({ title: err.message || "上传文件失败", icon: "none" });
    });
};

/**
 * 取私密文件查看 URL（小程序商家本人查看自己上传的证件 / 合同）。
 * 服务端会校验 path 必须以 wechat/merchant_private/{当前 user_id}/ 开头。
 *
 * @param {string} objectKey 存数据库的 path（带或不带前导 /）
 * @returns {Promise<{ url: string, expireSeconds: number }>}
 */
export const signPrivateView = (objectKey) => {
  return new Promise((resolve, reject) => {
    if (!objectKey) return reject(new Error("object_key 不能为空"));
    const cleanKey = objectKey.replace(/^\/+/, "");
    uni.request({
      url: RequsetUrl + "/api/v1/wechat/oss/sign-private-view",
      method: "POST",
      header: {
        Authorization: uni.getStorageSync("ctoken") || "",
        "Content-Type": "application/json",
      },
      data: { object_key: cleanKey },
      success: (res) => {
        if (res.statusCode !== 200) return reject(new Error("签发失败:" + res.statusCode));
        const body = res.data || {};
        const data = body.data || body;
        if (!data || !data.url) return reject(new Error("签发结果字段缺失"));
        resolve({ url: data.url, expireSeconds: data.expire_seconds });
      },
      fail: (err) => reject(err),
    });
  });
};
