/**
 * 微信内容安全检查（医生端小程序）
 * 调用 xk-api /api/doctor/content-security/* 接口
 */
import { req } from '@/common/js/index.js';
import { promptDoctorWxBind } from '@/common/js/wx-bind-helper.js';

/** 资料类场景（个人信息编辑） */
export const SCENE_PROFILE = 1;
/** 社交日志场景（聊天） */
export const SCENE_CHAT = 4;

/** 微信 msg_sec_check 单条内容上限 */
const MAX_TEXT_LEN = 2500;

/** 需先绑定微信的错误文案片段 */
const NEED_BIND_MSGS = ['请先绑定微信', '用户未绑定微信', '无法获取用户手机号', '绑定微信'];

/**
 * 从多种 reject 结构中提取错误文案（兼容 HTTP 4xx 拦截器固定 msg）
 */
function extractErrorMessage(err) {
  if (!err) {
    return '';
  }
  const direct = err.msg || err.message;
  if (direct && direct !== 'response 300-499') {
    return String(direct);
  }
  const resData = err.res && err.res.data;
  if (resData == null) {
    return '';
  }
  if (typeof resData === 'object') {
    return String(resData.message || resData.msg || '');
  }
  if (typeof resData === 'string') {
    try {
      const parsed = JSON.parse(resData);
      return String((parsed && (parsed.message || parsed.msg)) || '');
    } catch (e) {
      return '';
    }
  }
  return '';
}

/**
 * 判断是否为未绑定微信导致的检测失败
 */
export function isNeedBindError(err) {
  const msg = extractErrorMessage(err);
  return NEED_BIND_MSGS.some((item) => msg.includes(item));
}

/**
 * 未绑定时弹窗确认，用户同意则绑定并重试检测
 */
async function handleNeedBindAndRetry(retryFn) {
  const confirmed = await promptDoctorWxBind();
  if (!confirmed) {
    throw { msg: '已取消绑定，无法进行内容安全校验' };
  }
  return retryFn();
}

/**
 * 统一展示内容安全错误
 */
export function handleSecurityError(err) {
  const msg = extractErrorMessage(err) || '内容含有违规信息，请修改后重试';
  uni.showToast({ title: msg, icon: 'none' });
}

function assertCheckOk(res) {
  if (res && (res.code === 0 || res.errcode === 0)) {
    return true;
  }
  throw { msg: (res && (res.message || res.msg)) || '内容含有违规信息，请修改后重试' };
}

/**
 * 将字段值规范为可比较的字符串（数组用逗号拼接）
 */
function normalizeFieldValue(val) {
  if (val == null) {
    return '';
  }
  if (Array.isArray(val)) {
    return val.filter(Boolean).map((item) => String(item).trim()).filter(Boolean).join(',');
  }
  return String(val).trim();
}

/**
 * 与 baseline 对比，返回有变动且非空的文本列表
 * @param {Object} fields 当前表单字段 { key: value }
 * @param {Object} baseline 初始快照
 */
export function pickChangedTexts(fields, baseline = {}) {
  const texts = [];
  const base = baseline || {};
  Object.keys(fields || {}).forEach((key) => {
    const current = normalizeFieldValue(fields[key]);
    const original = normalizeFieldValue(base[key]);
    if (current && current !== original) {
      texts.push(current);
    }
  });
  return texts;
}

/**
 * 将多条文本用换行拼接；超过 2500 字则按字段拆成多批请求
 */
export function joinTextsForCheck(texts) {
  const list = (Array.isArray(texts) ? texts : [])
    .map((item) => String(item || '').trim())
    .filter(Boolean);
  if (!list.length) {
    return [];
  }
  const batches = [];
  let current = '';
  list.forEach((text) => {
    const merged = current ? `${current}\n${text}` : text;
    if (merged.length <= MAX_TEXT_LEN) {
      current = merged;
      return;
    }
    if (current) {
      batches.push(current);
      current = '';
    }
    if (text.length <= MAX_TEXT_LEN) {
      current = text;
    } else {
      // 单字段超长时按上限切分（就诊人场景几乎不会触发）
      for (let i = 0; i < text.length; i += MAX_TEXT_LEN) {
        batches.push(text.slice(i, i + MAX_TEXT_LEN));
      }
    }
  });
  if (current) {
    batches.push(current);
  }
  return batches;
}

/**
 * 表单提交前：仅检测变动字段，合并为一次或少量 msg_sec_check 调用
 */
export async function checkProfileTexts(fields, baseline, scene = SCENE_PROFILE) {
  const changed = pickChangedTexts(fields, baseline);
  if (!changed.length) {
    return true;
  }
  const batches = joinTextsForCheck(changed);
  for (let i = 0; i < batches.length; i++) {
    await checkText(batches[i], scene);
  }
  return true;
}

async function requestCheckText(content, scene) {
  const text = String(content || '').trim();
  if (!text) {
    return true;
  }
  const res = await req.request({
    url: '/newApi/content-security/check-text',
    method: 'POST',
    data: { content: text, scene },
  });
  return assertCheckOk(res);
}

/**
 * 文本内容安全检查（遇未绑定微信时弹窗确认后绑定并重试一次）
 */
export async function checkText(content, scene = SCENE_PROFILE) {
  try {
    return await requestCheckText(content, scene);
  } catch (e) {
    if (isNeedBindError(e)) {
      return handleNeedBindAndRetry(() => requestCheckText(content, scene));
    }
    throw e;
  }
}

/**
 * 批量文本检查（按顺序，每条独立请求；聊天等场景不适用合并检测）
 */
export async function checkTexts(texts, scene = SCENE_PROFILE) {
  const list = Array.isArray(texts) ? texts : [texts];
  for (let i = 0; i < list.length; i++) {
    const item = list[i];
    if (item) {
      await checkText(item, scene);
    }
  }
  return true;
}

async function requestCheckImage(filePath, scene) {
  return true;
  const res = await req.request({
    url: '/newApi/content-security/check-image',
    type: 'upload',
    method: 'POST',
    filePath,
    name: 'file',
    formData: { scene: String(scene) },
  });
  return assertCheckOk(res);
}

/**
 * 本地图片安全检查（遇未绑定微信时弹窗确认后绑定并重试一次）
 */
export async function checkImage(filePath, scene = SCENE_PROFILE) {
  if (!filePath) {
    return true;
  }
  try {
    return await requestCheckImage(filePath, scene);
  } catch (e) {
    if (isNeedBindError(e)) {
      return handleNeedBindAndRetry(() => requestCheckImage(filePath, scene));
    }
    throw e;
  }
}

async function requestCheckImageUrl(url, scene) {
  const res = await req.request({
    url: '/newApi/content-security/check-image-url',
    method: 'POST',
    data: { url, scene },
  });
  return assertCheckOk(res);
}

/**
 * 公网图片 URL 检查（遇未绑定微信时弹窗确认后绑定并重试一次）
 */
export async function checkImageUrl(url, scene = SCENE_PROFILE) {
  const imageUrl = String(url || '').trim();
  if (!imageUrl) {
    return true;
  }
  try {
    return await requestCheckImageUrl(imageUrl, scene);
  } catch (e) {
    if (isNeedBindError(e)) {
      return handleNeedBindAndRetry(() => requestCheckImageUrl(imageUrl, scene));
    }
    throw e;
  }
}
