/**
 * 解析让球方
 */
const ratioAccept = (ratio) => {
  if (ratio > 0) {
    return 'a';
  }
  return '';
}

/**
 * 将比率转换为字符串
 * @param {*} ratio
 * @returns
 */
const ratioString = (ratio) => {
  ratio = Math.abs(ratio);
  ratio = ratio.toString();
  ratio = ratio.replace(/\./, '');
  return ratio;
}

/**
 * 解析胜平负盘口
 * @param {*} moneyline
 * @returns
 */
const parseMoneyline = (moneyline) => {
  // 胜平负
  if (!moneyline) {
    return null;
  }
  const { home, away, draw } = moneyline;
  return {
    'ior_mh': { v: home },
    'ior_mc': { v: away },
    'ior_mn': { v: draw },
  }
}

/**
 * 解析让分盘口
 * @param {*} spreads
 * @param {*} wm
 * @returns
 */
const parseSpreads = (spreads, wm) => {
  // 让分盘
  if (!spreads?.length) {
    return null;
  }
  const events = {};
  spreads.forEach(spread => {
    const { hdp, home, away } = spread;

    // if (!(hdp % 1) || !!(hdp % 0.5)) {
    //   // 整数或不能被0.5整除的让分盘不处理
    //   return;
    // }

    const ratio_ro = hdp;
    const ratio_r = ratio_ro - wm;
    events[`ior_r${ratioAccept(ratio_r)}h_${ratioString(ratio_r)}`] = {
      v: home,
      r: wm != 0 ? `ior_r${ratioAccept(ratio_ro)}h_${ratioString(ratio_ro)}` : undefined
    };
    events[`ior_r${ratioAccept(-ratio_r)}c_${ratioString(ratio_r)}`] = {
      v: away,
      r: wm != 0 ? `ior_r${ratioAccept(-ratio_ro)}c_${ratioString(ratio_ro)}` : undefined
    };
  });
  return events;
}

/**
 * 解析大小球盘口
 * @param {*} totals
 * @returns
 */
const parseTotals = (totals) => {
  // 大小球盘
  if (!totals?.length) {
    return null;
  }
  const events = {};

  totals.forEach(total => {
    const { points, over, under } = total;
    events[`ior_ouc_${ratioString(points)}`] = { v: over };
    events[`ior_ouh_${ratioString(points)}`] = { v: under };
  });
  return events;
}

/**
 * 解析直赛盘口
 * @param {*} straight
 * @param {*} wm
 * @returns
 */
const parseStraight = (straight, wm) => {
  if (!straight) {
    return null;
  }
  const { cutoff='', status=0, spreads=[], moneyline={}, totals=[] } = straight;
  const cutoffTime = new Date(cutoff).getTime();
  const nowTime = Date.now();

  if (status != 1 || cutoffTime < nowTime) {
    return null;
  }

  const events = {};
  Object.assign(events, parseSpreads(spreads, wm));
  Object.assign(events, parseMoneyline(moneyline));
  Object.assign(events, parseTotals(totals));

  return events;
}

/**
 * 解析净胜球盘口
 * @param {*} winningMargin
 * @param {*} home
 * @param {*} away
 * @returns
 */
const parseWinningMargin = (winningMargin, home, away) => {
  if (!winningMargin) {
    return null;
  }
  const { cutoff='', status='', contestants=[] } = winningMargin;
  const cutoffTime = new Date(cutoff).getTime();
  const nowTime = Date.now();

  if (status != 'O' || cutoffTime < nowTime || !contestants?.length) {
    return null;
  }

  const events = {};
  contestants.forEach(contestant => {
    const { name, price } = contestant;
    const nr = name.match(/\d+$/)?.[0];
    if (!nr) {
      return;
    }
    let side;
    if (name.startsWith(home)) {
      side = 'h';
    }
    else if (name.startsWith(away)) {
      side = 'c';
    }
    else {
      return;
    }
    events[`ior_wm${side}_${nr}`] = { v: price };
  });
  return events;
}

/**
 * 解析进球数盘口
 * @param {*} exactTotalGoals
 * @returns
 */
const parseExactTotalGoals = (exactTotalGoals) => {
  if (!exactTotalGoals) {
    return null;
  }
  const { cutoff='', status='', contestants=[] } = exactTotalGoals;
  const cutoffTime = new Date(cutoff).getTime();
  const nowTime = Date.now();

  if (status != 'O' || cutoffTime < nowTime || !contestants?.length) {
    return null;
  }

  const events = {};
  contestants.forEach(contestant => {
    const { name, price } = contestant;
    if (+name >= 1 && +name <= 7) {
      events[`ior_ot_${name}`] = { v: price };
    }
  });
  return events;
}

/**
 * 解析滚球场次状态
 * @param {*} state
 * @returns
 */
const parseRbState = (state) => {
  let stage = null;
  if (state == 1) {
    stage = '1H';
  }
  else if (state == 2) {
    stage = 'HT';
  }
  else if (state == 3) {
    stage = '2H';
  }
  else if (state >= 4) {
    stage = 'ET';
  }
  return stage;
}

/**
 * 解析比赛数据
 * @param {*} game
 * @returns
 */
export const parseGame = (game, filtedGames) => {
  const { eventId=0, originId=0, periods={}, specials={}, home, away, marketType, state, elapsed, homeScore=0, awayScore=0 } = game;
  const { straight, straight1st } = periods;
  const { winningMargin={}, exactTotalGoals={}, winningMargin1st={}, exactTotalGoals1st={} } = specials;
  const filtedGamesSet = new Set(filtedGames);
  const wm = homeScore - awayScore;
  const score = `${homeScore}-${awayScore}`;
  const events = parseStraight(straight, wm) ?? {};
  const stage = parseRbState(state);
  const retime = elapsed ? `${elapsed}'` : '';
  const evtime = Date.now();
  Object.assign(events, parseWinningMargin(winningMargin, home, away));
  Object.assign(events, parseExactTotalGoals(exactTotalGoals));
  const gameInfos = [];
  gameInfos.push({ eventId, originId, events, evtime, stage, retime, score, wm, marketType });
  const halfEventId = eventId * -1;
  if (filtedGamesSet.has(halfEventId)) {
    const events = parseStraight(straight1st, wm) ?? {};
    Object.assign(events, parseWinningMargin(winningMargin1st, home, away));
    Object.assign(events, parseExactTotalGoals(exactTotalGoals1st));
    gameInfos.push({ eventId: halfEventId, originId, events, evtime, stage, retime, score, wm, marketType });
  }
  return gameInfos;
}

/*
* 解析比率信息
*/
const parseRatio = (ratioString) => {
 if (!ratioString) {
   return null;
 }
 return parseFloat(`${ratioString[0]}.${ratioString.slice(1)}`);
}

/**
 * 解析盘口信息
 * @param {*} ior
 * @returns
 */
const parseIor = (ior) => {
 const iorMatch = ior.match(/ior_(m|r|ou|wm|ot)([ao])?([hcn])?_?(\d+)?/);
 if (!iorMatch) {
   return null;
 }
 const [, type, action, side, ratio] = iorMatch;
 return { type, action, side, ratio };
}

/**
 * 解析盘口详情
 * @param {*} ior
 * @param {*} id
 * @param {*} gamesMap
 * @returns
 */
export const parseIorDetail = (ior, id, gamesMap) => {
  const gamesData = gamesMap[id];
  if (!gamesData) {
    return { ior, id, message: 'games data not found', cause: 400 };
  }
  const iorOptions = parseIor(ior);
  if (!iorOptions) {
    return { ior, id, message: 'ior options not found', cause: 400 };
  }
  const { type, action, side, ratio } = iorOptions;

  const { leagueId, id: eventId, home: homeTeamName, away: awayTeamName, periods={}, specials={}} = gamesData;

  const straightData = periods.straight ?? {};
  const { lineId: straightLineId, moneyline, spreads, totals } = straightData;
  const { winningMargin, exactTotalGoals } = specials;

  if (type === 'm' && moneyline && !action && !ratio) {
    const sideKey = side === 'h' ? 'home' : side === 'c' ? 'away' : 'draw';
    const team = side === 'h' ? 'TEAM1' : side === 'c' ? 'TEAM2' : 'DRAW';
    const odds = moneyline[sideKey];
    return { leagueId, eventId, betType: 'MONEYLINE', team, lineId: straightLineId, odds };
  }

  else if (type === 'r' && spreads) {
    let ratioDirection = 1;
    if (side === 'c' && action === 'a' || side === 'h' && !action) {
      ratioDirection = -1;
    }
    const ratioKey = parseRatio(ratio) * ratioDirection;
    const itemSpread = spreads.find(spread => spread.hdp == ratioKey);
    if (!itemSpread) {
      return { ior, id, message: 'item spread not found', cause: 400 };
    }
    const { altLineId=null, home, away } = itemSpread;
    const odds = side === 'h' ? home : away;
    const team = side === 'h' ? 'TEAM1' : 'TEAM2';
    const handicap = ratioKey * (side === 'h' ? 1 : -1);
    return { leagueId, eventId, handicap, betType: 'SPREAD', team, lineId: straightLineId, altLineId, odds };
  }

  else if (type === 'ou' && totals) {
    const ratioKey = parseRatio(ratio);
    const itemTotal = totals.find(total => total.points == ratioKey);
    if (!itemTotal) {
      return { ior, id, message: 'item total not found', cause: 400 };
    }
    const { altLineId=null, over, under } = itemTotal;
    const odds = side === 'c' ? over : under;
    const sideKey = side === 'c' ? 'OVER' : 'UNDER';
    return { leagueId, eventId, handicap: ratioKey, betType: 'TOTAL_POINTS', side: sideKey, lineId: straightLineId, altLineId, odds };
  }

  else if (type === 'wm' && winningMargin) {
    const ratioKey = parseRatio(ratio);
    const { id: specialId } = winningMargin;
    const wmName = side === 'h' ? `${homeTeamName} By ${ratioKey}` : side === 'c' ? `${awayTeamName} By ${ratioKey}` : '';
    const wmItem = winningMargin.contestants.find(contestant => contestant.name == wmName);
    if (!wmItem) {
      return { ior, id, message: 'item winning margin not found', cause: 400 };
    }
    const { id: contestantId, lineId, price } = wmItem;
    return { leagueId, eventId, specialId, contestantId, lineId, odds: price };
  }

  else if (type === 'ot' && exactTotalGoals) {
    const ratioKey = parseRatio(ratio);
    const { id: specialId } = exactTotalGoals;
    const otItem = exactTotalGoals.contestants.find(contestant => contestant.name == ratioKey);
    if (!otItem) {
      Logs.outDev('pinnacle item exact total goals not found', id, type, action, side, ratio);
      return { ior, id, message: 'item exact total goals not found', cause: 400 };
    }
    const { id: contestantId, lineId, price } = otItem;
    return { leagueId, eventId, specialId, contestantId, lineId, odds: price };
  }

  else {
    return { ior, id, message: 'ior type not found', cause: 400 };
  }
}
