import {findArray, stringToArray, tryRun} from '@/tool';

export class ReasonableSafeMedicine {
  constructor(sort = ReasonableSafeMedicine.sort) {
    this.sort = sort;
  }

  analysis(medicines) { return ReasonableSafeMedicine.analysis(medicines, {sort: this.sort}); }


  static config = [
    {field: 'rs@10.1', key: 'lowDose', name: '剂量偏低', highlight: {value: true}},
    {field: 'rs@10.2', key: 'overDose', name: '剂量偏高', highlight: {value: true}},
    {field: 'rs@10', key: '', name: '超剂量药品', highlight: {value: true}},
    {field: 'rs@02', key: 'taboo', name: '慎忌禁用药'},
    {field: 'rs@03', key: 'pregnantTaboo', name: '孕妇慎忌禁'},
    {field: 'rs@04', key: 'diet', name: '服药饮食禁忌'},
    {field: 'rs@05', key: 'toxicity', name: '药物毒性说明', highlight: {label: true}},
    {field: 'rs@06', key: 'disSyn', name: '病证用药禁忌'},
    {field: 'rs@07', key: 'sbf', name: '十八反', highlight: {label: true}},
    {field: 'rs@08', key: 'sjw', name: '十九畏', highlight: {label: true}},
    {field: 'rs@09', key: 'by', name: '用药不宜'},
    {field: 'rs@00', key: 'prepare', name: '炮制品'},
  ];
  static sort = '10,2,3,4,5,6,7,8,9';

  /**
   * 解析药品的合理安全用药数据
   * @param medicines 药品
   * @param {object} [config] 配置信息
   * @param {string} [config.filter] 过滤规则
   * @param {string} [config.sort] 排序规则
   * @return {Readonly<{
   *  [key: string]: { name: string; collection: Set<string>; gather: Set<string>; highlight?: {label: boolean; value: boolean;} }
   *  toString(): string
   * }>}
   */
  static analysis(medicines, config = {}) {
    const sort = stringToArray(config.filter || config.sort || this.sort);
    const data = {
      * [Symbol.iterator]() { for (const key of sort) if (this[key]) yield this[key]; },
      sign() {
        const gather = new Set()
        for (const item of this) item.gather.forEach(value => gather.add(value));
        return Array.from(gather);
      },
      toString() {
        const parse = (value, highlight) => {
          const match = value.match(/^(.+?)(\d+(?:\.\d+)?[克Gg]?|反|畏|不宜与)?[(（]([\s\S]*)[）)]$/);
          if (!match) return value;

          const [_, prefix = value, dosage, suffix] = match;
          return [
            `<span class="${highlight.label && 'highlight'}">${prefix}</span>`,
            dosage ? `<span>${dosage}</span>` : '',
            suffix ? `<span class="${highlight.value && 'highlight'}">(${suffix})</span>` : '',
          ].filter(Boolean).join(' ');
        };
        let html = ``;
        for (const {name, highlight = {}, collection} of this) {
          html += `
            <div class="item">
                <div class="label">${name}：</div>
                ${Array.from(collection, item => `
                    <div class="value">${parse(item, highlight)}</div>
                `).join('')}
            </div>
          `;
        }
        return html;
      },
    };
    Object.defineProperty(data, 'sign', {enumerable: false, writable: true, configurable: true});
    Object.defineProperty(data, 'toString', {enumerable: false, writable: true, configurable: true});

    const append = (key, value, id) => {
      if (!value) return '';
      const config = findArray(this.config, ['field', `rs@${key}`]);
      if (config) {
        const child = data[+key] || (data[+key] = {...config, collection: new Set(), gather: new Set()});
        stringToArray(value, '|', (v) => child.collection.add(v));
        if (id) child.gather.add(id);
      }
    };
    for (const medicine of medicines) {
      for (const field of Object.keys(medicine)) {
        const match = field.match(/rs@(\d+)(?:\.(\d+))?$/);
        if (!match) continue;
        const [_, category, subcategory] = match;
        append(category, medicine[field], medicine.matid);
        if (subcategory) append(`${category}.${subcategory}`, medicine[field], medicine.matid);
      }
    }
    return Object.freeze(data);
  }
}