const Logs = require('../libs/logs');
const IOR_KEYS_MAP = require('./iorKeys');

const GOLD_BASE = 10000;
const WIN_MIN = process.env.NODE_ENV == 'development' ? -10000 : -1200;
const JC_REBATE_RATIO = 0;

/**
 * 筛选最优赔率
 */
function getOptimalSelections(data, combos) {
  const results = [];

  combos.forEach((rule, index) => {
    let validOptions = [];

    for (let i = 0; i < 3; i++) {
      const jcIndex = i;
      const selection = [];
      let isValid = true;
      for (let j = 0; j < 3; j++) {
        const key = rule[j];
        const item = data[key];

        if (!item) {
          isValid = false;
          break;
        }
        if (j === jcIndex) {
          if (!('jc' in item)) {
            isValid = false;
            break;
          }
          selection.push({
            k: key,
            p: 'jc',
            v: item.jc,
            o: item,
          });
        }
        else {
          const candidates = ['ps', 'ob'].filter((k) => k in item);
          if (candidates.length === 0) {
            isValid = false;
            break;
          }
          const best = candidates.reduce((a, b) => item[a] > item[b] ? a : b);
          selection.push({
            k: key,
            p: best,
            v: item[best],
            o: item,
          });
        }
      }

      if (isValid) {
        validOptions.push(selection);
      }
    }

    if (validOptions.length > 0) {
      const iors = validOptions.reduce((a, b) => {
        const sumA = a.reduce((sum, x) => sum + x.v, 0);
        const sumB = b.reduce((sum, x) => sum + x.v, 0);
        return sumA > sumB ? a : b;
      });
      results.push({ rule, iors, index });
    }
  });

  return results;
}

/**
 * 精确浮点数字
 * @param {number} number
 * @param {number} x
 * @returns {number}
 */
const fixFloat = (number, x=2) => {
  return parseFloat(number.toFixed(x));
}

/**
 * 计算盈利
 */
const triangleProfitCalc = (goldsInfo, oddsOption) => {
  const {
    gold_side_a: x,
    gold_side_b: y,
    gold_side_m: z,
    odds_side_a: a,
    odds_side_b: b,
    odds_side_m: c
  } = goldsInfo;

  const { crossType, jcIndex } = oddsOption;
  /**
   * crossType:
   *  la: 全输
   *  wa: 全赢
   *  lh: 半输
   *  wh: 半赢
   *  dr: 和局
   *  la_wh_wa, la_dr_wa, la_lh_wa, lh_dr_wa, lh_lh_wa, la_la_wa
   */

  let jc_rebate = 0;
  if (jcIndex == 0) {
    jc_rebate = x * JC_REBATE_RATIO;
  }
  else if (jcIndex == 1) {
    jc_rebate = y * JC_REBATE_RATIO;
  }
  else if (jcIndex == 2) {
    jc_rebate = z * JC_REBATE_RATIO;
  }

  let win_side_a = 0, win_side_b = 0, win_side_m = 0;
  win_side_a = a * x - y - z;
  win_side_b = b * y - x - z;

  switch (crossType) {
    case 'la_wh_wa': // 全输 半赢 全赢
      win_side_m = c*z - x + b*y/2;
      break;
    case 'la_dr_wa': // 全输 和局 全赢
      win_side_m = c*z - x;
      break;
    case 'la_lh_wa': // 全输 半输 全赢
      win_side_m = c*z - x - y/2;
      break;
    case 'lh_dr_wa': // 半输 和局 全赢
      win_side_m = c*z - x/2;
      break;
    case 'lh_lh_wa': // 半输 半输 全赢
      win_side_m = c*z - x/2 - y/2;
      break;
    case 'la_la_wa': // 全输 全输 全赢
      win_side_m = c*z - x - y;
      break;
  }

  win_side_a = fixFloat(win_side_a + jc_rebate);
  win_side_b = fixFloat(win_side_b + jc_rebate);
  win_side_m = fixFloat(win_side_m + jc_rebate);
  const win_average = fixFloat((win_side_a + win_side_b + win_side_m) / 3);

  return { win_side_a, win_side_b, win_side_m, win_average }
}

const triangleGoldCalc = (oddsInfo, oddsOption) => {
  const { odds_side_a: a, odds_side_b: b, odds_side_m: c } = oddsInfo;
  if (!a || !b || !c) {
    return;
  }
  const { crossType, jcIndex } = oddsOption;
  let x = GOLD_BASE;
  let y = (a + 1) * x / (b + 1);
  let z;
  switch (crossType) {
    case 'la_wh_wa': // 全输 半赢 全赢
      z = b * y / 2 / (c + 1);
      break;
    case 'la_dr_wa': // 全输 和局 全赢
      z = b * y / (c + 1);
      break;
    case 'la_lh_wa': // 全输 半输 全赢
      z = (2 * b + 1) * y / 2 / (c + 1);
      break;
    case 'lh_dr_wa': // 半输 和局 全赢
      z = (b * y - x / 2) / (c + 1);
      break;
    case 'lh_lh_wa': // 半输 半输 全赢
      z = (b * y + y / 2 - x / 2) / (c + 1);
      break;
    case 'la_la_wa': // 全输 全输 全赢
      z = (b + 1) * y / (c + 1);
      break;
    default:
      z = 0;
  }

  if (jcIndex == 1) {
    const scale = GOLD_BASE / y;
    x = x * scale;
    y = GOLD_BASE;
    z = z * scale;
  }
  else if (jcIndex == 2) {
    const scale = GOLD_BASE / z;
    x = x * scale;
    y = y * scale;
    z = GOLD_BASE;
  }

  return {
    gold_side_a: x,
    gold_side_b: fixFloat(y),
    gold_side_m: fixFloat(z),
    odds_side_a: a,
    odds_side_b: b,
    odds_side_m: c,
  };

}

const eventSolutions = (oddsInfo, oddsOption) => {
  const goldsInfo = triangleGoldCalc(oddsInfo, oddsOption);
  if (!goldsInfo) {
    return;
  }
  const profitInfo = triangleProfitCalc(goldsInfo, oddsOption);
  // console.log(goldsInfo, profitInfo);
  return {
    ...goldsInfo,
    ...profitInfo,
    cross_type: oddsOption.crossType,
    jc_index: oddsOption.jcIndex,
  }
}

const eventsCombination = (passableEvents) => {
  const solutions = [];
  passableEvents.forEach(events => {
    const { odds, info } = events;
    Object.keys(IOR_KEYS_MAP).forEach(group => {
      const rules = IOR_KEYS_MAP[group];
      const optimalSelections = getOptimalSelections(odds, rules);
      optimalSelections.forEach(selection => {
        const { rule, iors, index } = selection;
        const [, , , crossType] = rule;

        const oddsSideA = iors[0];
        const oddsSideB = iors[1];
        const oddsSideM = iors[2];
        const jcIndex = iors.findIndex(item => item.p == 'jc');
        if (!oddsSideA || !oddsSideB || !oddsSideM) {
          return;
        }
        const cpr = [ oddsSideA, oddsSideB, oddsSideM ];
        const oddsInfo = {
          odds_side_a: fixFloat(oddsSideA.v - 1),
          odds_side_b: fixFloat(oddsSideB.v - 1),
          odds_side_m: fixFloat(oddsSideM.v - 1)
        };
        const oddsOption = { crossType, jcIndex };
        const sol = eventSolutions(oddsInfo, oddsOption);
        if (sol?.win_average > WIN_MIN) {
          const id = info.id;
          const keys = cpr.map(item => `${item.k}`).join('_');
          const sid = `${id}_${keys}`;
          const timestamp = Date.now();
          solutions.push({sid, sol, cpr, info, rule: `${group}:${index}`, timestamp});
        }
      });
    });
  });
  return solutions;
}

module.exports = eventsCombination;