import dayjs from 'dayjs';
import { toast } from '@/utils/widget';
import validate from "@/utils/validate";

const FormRule = {
  date: checkDate,
  input: checkInput,
  radio: checkListItem,
  select: checkListItem,
  textarea: checkInput,
  selectMobile: checkInput,
  selectAndOther: checkInput,
  selectAndImage: checkListItem,
  multiSelectAndOther: checkMultiList,
  tagPicker: checkMultiList,
  files: checkFiles,
  runTime: checkInput,
}

const fixedRule = {
  mobile: checkMobile,
  idCard: checkIdCard,
}


export default function verify(items, rule = {}, data = {}) {
  const rules = { ...fixedRule, ...rule };
  for (let item of items) {
    const value = data[item.title];
    // 非自定义表单 数据验证
    if (item.operateType === 'formCell' && FormRule[item.type]) {
      const valid = FormRule[item.type](item, value);
      if (!valid) return false
    }
    // 自定义校验规则 检验表单
    // 自定义校验表单规则 必须是函数且返回结果只能是 错误信息或者 true
    if (typeof rules[item.title] === 'function') {
      const res = rules[item.title](value, item.name);
      if (typeof res === 'string') {
        toast(res);
        return false
      } else if (res !== true) {
        console.error('自定义检验规则只能返回 字符串或者true')
      }
    }
  }
  return true
}

function checkDate({ name, required }, value) {
  if (!required && !isTrueValue(value)) return true;
  if (required && !isTrueValue(value)) {
    toast(`请选择${name}`)
    return false
  }
  if (!dayjs(value).isValid()) {
    toast(`${name}格式不正确`)
    return false
  }
  return true
}

function checkListItem({ range, name, required }, value) {
  if (isTrueValue(value)) {
    if (!Array.isArray(range) || range.length === 0) {
      toast(`${name}所选值无效，请重新选择`)
      return false
    }
    const candidate = typeof value === 'string' || typeof value === 'number' ? String(value) : value;
    const isObjectRange = range.length > 0 && range[0] && typeof range[0] === 'object';
    if (isObjectRange) {
      const values = range
        .map((i) => (i && typeof i === 'object' && 'value' in i ? i.value : undefined))
        .filter((i) => i !== undefined && i !== null)
        .map((i) => String(i));
      if (!values.includes(String(candidate))) {
        toast(`${name}所选值无效，请重新选择`)
        return false
      }
    } else if (!range.map((i) => String(i)).includes(String(candidate))) {
      toast(`${name}所选值无效，请重新选择`)
      return false
    }
  } else {
    if (required) {
      toast(`请选择${name}`)
      return false
    }
  }
  return true
}

function checkMobile(value, name) {
  if (isTrueValue(value)) {
    const res = validate.isMobile(value);
    if (res) return true;
    else return `${name}格式不正确`
  }
  return true
}

function checkIdCard(value, name) {
  if (isTrueValue(value)) {
    const [res, msg] = validate.isChinaId(value);
    if (res) return true;
    else return msg || `${name}格式不正确`
  }
  return true
}

function checkInput({ name, required, wordLimit, inputType }, value) {
  if (!required && !isTrueValue(value)) return true;
  if (required && !isTrueValue(value)) {
    toast(`请输入${name}`)
    return false
  }
  if (wordLimit > 0 && inputType === 'text' && value.toString().length > wordLimit) {
    toast(`${name}最多输入${wordLimit}个字符`)
    return false
  }
  return true
}

function checkMultiList({ name, required }, value) {
  const list = Array.isArray(value) ? value.filter(isTrueValue) : [];
  if (required && list.length === 0) {
    toast(`请选择${name}`)
    return false
  }
  return true
}

function checkFiles({ name, required }, value) {
  const list = Array.isArray(value)
    ? value
      .map((i) => {
        if (typeof i === 'string') return i;
        if (i && typeof i === 'object' && i.url) return String(i.url);
        return '';
      })
      .filter((i) => typeof i === 'string' && i.trim() !== '')
    : typeof value === 'string' && value.trim() !== ''
      ? [value]
      : [];
  if (required && list.length === 0) {
    toast(`请上传${name}`)
    return false
  }
  return true
}

function isTrueValue(value) {
  if (typeof value === 'string') return value.trim() !== '';
  if (typeof value === 'number') return true;
  return Boolean(value)
}
