/**
 * 处方价格计算工具类
 * 职责：统一管理处方价格计算逻辑
 */

/**
 * 与后端 format_price 一致：第三位小数非 0 则分位进 1，再保留两位小数
 */
export function formatPriceLikeBackend(value) {
  const price = parseFloat(value || 0);
  if (Number.isNaN(price)) {
    return 0;
  }
  let milli = Math.round(price * 1000);
  if (milli % 10 > 0) {
    milli += 10;
  }
  milli -= milli % 10;
  return Math.round((milli / 1000) * 100) / 100;
  // return milli / 1000;
}

/** 模拟 PHP bcmul 在指定 scale 下向零截断 */
function bcmulScale(a, b, scale) {
  const product = parseFloat(a || 0) * parseFloat(b || 0);
  const factor = 10 ** scale;
  return Math.trunc(product * factor) / factor;
}

/** 模拟 PHP bcadd 在指定 scale 下向零截断 */
function bcaddScale(a, b, scale) {
  const sum = a + b;
  const factor = 10 ** scale;
  return Math.trunc(sum * factor) / factor;
}

/**
 * 中药商品总价（与 PrescriptionService::createChineseReprice 一致）
 */
export function calculateChineseMedicineProductPriceLikeBackend(drugs, dosage = 7) {
  if (!drugs || drugs.length === 0) {
    return 0;
  }
  const dose = parseFloat(dosage || 0);
  let total = 0;
  for (const drug of drugs) {
    const linePerDose = bcmulScale(drug.price, drug.number ?? 1, 3);
    const lineTotal = bcmulScale(dose, linePerDose, 3);
    total = bcaddScale(total, lineTotal, 3);
  }
  return formatPriceLikeBackend(total);
}

export class PrescriptionCalculator {
  /**
   * 计算中药商品总价
   * @param {Array} drugs - 药品列表
   * @param {number} dosage - 剂数（天数）
   * @returns {number} 商品总价
   */
  static calculateChineseMedicineProductPrice(drugs, dosage = 7) {
    return calculateChineseMedicineProductPriceLikeBackend(drugs, dosage);
  }

  static isValidBuyPrice(value) {
    if (value === null || value === undefined || value === '') {
      return false;
    }
    const n = parseFloat(value);
    return !Number.isNaN(n);
  }

  /**
   * 计算中药商品供货总价（仅含有效 buy_price 的药品）
   */
  static calculateChineseMedicineBuyTotal(drugs, dosage = 7) {
    if (!drugs || drugs.length === 0) {
      return 0;
    }
    return drugs.reduce((sum, drug) => {
      if (!this.isValidBuyPrice(drug.buy_price)) {
        return sum;
      }
      const buyPrice = parseFloat(drug.buy_price);
      const quantity = parseFloat(drug.number ?? drug.select_number ?? 1);
      return sum + (buyPrice * quantity * dosage);
    }, 0);
  }

  /**
   * 汇总毛利率（仅商品计费；任一味缺 buy_price 返回 --）
   */
  static calculateChineseTotalGrossMarginPercent(drugs, dosage = 7) {
    if (!drugs || drugs.length === 0 || dosage <= 0) {
      return '0.00';
    }
    let saleTotal = 0;
    let buyTotal = 0;
    for (const drug of drugs) {
      if (!this.isValidBuyPrice(drug.buy_price)) {
        return '--';
      }
      const qty = parseFloat(drug.number ?? drug.select_number ?? 1);
      const price = parseFloat(drug.price || 0);
      const buyPrice = parseFloat(drug.buy_price);
      saleTotal += price * qty * dosage;
      buyTotal += buyPrice * qty * dosage;
    }
    return this.calculateChineseGrossMarginPercent(saleTotal, buyTotal);
  }

  /**
   * 汇总毛利率（仅商品计费）
   */
  static calculateChineseGrossMarginPercent(saleTotal, buyTotal) {
    const sale = parseFloat(saleTotal);
    const buy = parseFloat(buyTotal);
    if (!sale || sale <= 0) {
      return '0.00';
    }
    return (((sale - buy) / sale) * 100).toFixed(2);
  }

  /**
   * 单味药毛利率
   */
  static calculateItemGrossMarginPercent(price, buyPrice) {
    const p = parseFloat(price);
    if (!p || p <= 0 || !this.isValidBuyPrice(buyPrice)) {
      return '--';
    }
    const b = parseFloat(buyPrice);
    return (((p - b) / p) * 100).toFixed(2);
  }

  /**
   * 计算西药商品总价
   * @param {Array} drugs - 药品列表
   * @returns {number} 商品总价
   */
  static calculateWesternMedicineProductPrice(drugs) {
    if (!drugs || drugs.length === 0) {
      return 0;
    }
    return drugs.reduce((sum, drug) => {
      const price = parseFloat(drug.price || 0);
      const quantity = parseFloat(drug.select_number || drug.number || 1);
      return sum + (price * quantity);
    }, 0);
  }

  /**
   * 计算简单产品总价（保健食品、服务包、非药品、医疗器械）
   * @param {Array} products - 产品列表
   * @returns {number} 商品总价
   */
  static calculateSimpleProductPrice(products) {
    if (!products || products.length === 0) {
      return 0;
    }
    return products.reduce((sum, product) => {
      const price = parseFloat(product.price || 0);
      const quantity = parseFloat(product.select_number || product.number || 1);
      return sum + (price * quantity);
    }, 0);
  }

  /**
   * 计算加工费（委托调剂）
   * @param {Object} processRule - 加工规则对象
   * @param {number} dosage - 剂数
   * @param {number} totalDrugQuantity - 总药品数量（用于按数量计算）
   * @returns {number} 加工费
   */
  static calculateProcessingFee(processRule, dosage = 7, totalDrugQuantity = 0) {
    if (!processRule || !processRule.calc_method) {
      return 0;
    }

    const calcMethod = processRule.calc_method; // 1=固定价格，2=按剂数，3=按数量
    const price = parseFloat(processRule.price || 0);

    switch (calcMethod) {
      case 1:
        // 固定价格
        return price;
      case 2:
        // 按剂数计算
        return price * dosage;
      case 3:
        // 按数量计算
        return price * dosage * totalDrugQuantity;
      default:
        return 0;
    }
  }

  /**
   * 计算处方总价
   * @param {Object} params - 计算参数
   * @param {number} params.category - 处方类型
   * @param {Array} params.drugs - 药品列表
   * @param {number} params.dosage - 剂数（中药需要）
   * @param {number} params.processingFee - 加工费（委托调剂需要）
   * @param {number} params.treatmentPrice - 诊疗费
   * @returns {number} 总价
   */
  static calculateTotalPrice(params) {
    const { category, drugs, dosage = 7, processingFee = 0, treatmentPrice = 0 } = params;

    let productPrice = 0;

    // 根据类型计算商品价格
    if (category === 1) {
      // 中药
      productPrice = this.calculateChineseMedicineProductPrice(drugs, dosage);
    } else if (category === 2) {
      // 西药
      productPrice = this.calculateWesternMedicineProductPrice(drugs);
    } else if ([3, 5, 6, 7].includes(category)) {
      // 简单产品
      productPrice = this.calculateSimpleProductPrice(drugs);
    }

    // 总价 = 商品价格 + 加工费 + 诊疗费
    const total = productPrice + processingFee + treatmentPrice;
    return parseFloat(total.toFixed(2));
  }
}
