/**
 * 볼링 점수 기반 순위 계산 유틸리티
 * 다양한 이벤트 유형(개인전, 팀전)에 대한 순위 계산 함수 제공
 */

// ================ 점수 계산 함수 ================

/**
 * 멤버별 평균 점수 계산 (입력된 점수만 평균, 소수점 1자리)
 * @param {Object} member - 참가자 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Number} - 참가자의 평균 점수
 */
export const calculateMemberAverageScore = (member, scoresProxy, gameCount) => {
  if (!member || !member.participantId || !gameCount) return 0;
  
  let total = 0, count = 0;
  const handicap = Number(member.handicap) || 0;
  
  // 각 게임별 점수 합산 및 플레이한 게임 수 카운트
  for (let i = 1; i <= gameCount; i++) {
    const scoreKey = `${member.participantId}-${i}`;
    const score = scoresProxy[scoreKey];
    
    if (score !== undefined && score !== null && score !== '' && !isNaN(Number(score))) {
      total += Number(score) + handicap;
      count++;
    }
  }
  
  return count > 0 ? Math.round((total / count) * 10) / 10 : 0;
};

/**
 * 팀 게임별 총점 계산 함수
 * @param {Object} team - 팀 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameNumber - 게임 번호
 * @returns {Number} - 해당 게임의 팀 총점
 */
export const calculateTeamGameScore = (team, scoresProxy, gameNumber) => {
  if (!team || !team.members) return 0;
  
  let total = 0;
  
  // 팀원들의 점수 합산
  team.members.forEach(member => {
    if (!member || !member.participantId) return;
    
    const scoreKey = `${member.participantId}-${gameNumber}`;
    const score = scoresProxy[scoreKey];
    
    if (score !== undefined && score !== null && score !== '') {
      // 핸디캡 우선순위: scoresProxy -handicap > member.scores[gameNumber-1]?.handicap > member.handicap
      let gameHandicap = null;
      
      if (scoresProxy[scoreKey + '-handicap'] !== undefined) {
        gameHandicap = Number(scoresProxy[scoreKey + '-handicap']) || 0;
      } else if (member.scores && member.scores[gameNumber-1] && typeof member.scores[gameNumber-1].handicap !== 'undefined') {
        gameHandicap = Number(member.scores[gameNumber-1].handicap) || 0;
      } else {
        gameHandicap = Number(member.handicap) || 0;
      }
      
      total += Number(score) + gameHandicap;
    }
  });
  
  // 팀 핸디캡 추가
  total += Number(team.handicap) || 0;
  
  return total;
};

/**
 * 팀 총 핸디캡 계산 함수
 * @param {Object} team - 팀 객체
 * @returns {Number} - 팀의 총 핸디캡
 */
export const calculateTeamTotalHandicap = (team) => {
  if (!team || !team.members) return 0;
  
  let total = 0;
  
  // 팀원들의 핸디캡 합산
  team.members.forEach(member => {
    const memberHc = Number(member.handicap) || 0;
    total += memberHc;
  });
  
  // 팀 핸디캡 추가
  total += Number(team.handicap) || 0;
  
  return total;
};

/**
 * 참가자 총점 계산 함수
 * @param {Object} participant - 참가자 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Number} - 참가자의 총점
 */
export const calculateParticipantTotalScore = (participant, scoresProxy, gameCount) => {
  if (!participant || !participant.participantId) return 0;
  
  let total = 0;
  
  // 각 게임별 점수 합산
  for (let i = 1; i <= gameCount; i++) {
    const scoreKey = `${participant.participantId}-${i}`;
    const score = scoresProxy[scoreKey];
    
    if (score !== undefined && score !== null && score !== '') {
      // 핸디캡 우선순위: scoresProxy -handicap > member.scores[i-1]?.handicap > member.handicap
      let gameHandicap = null;
      
      if (scoresProxy[scoreKey + '-handicap'] !== undefined) {
        gameHandicap = Number(scoresProxy[scoreKey + '-handicap']) || 0;
      } else if (participant.scores && participant.scores[i-1] && typeof participant.scores[i-1].handicap !== 'undefined') {
        gameHandicap = Number(participant.scores[i-1].handicap) || 0;
      } else {
        gameHandicap = Number(participant.handicap) || 0;
      }
      
      total += Number(score) + gameHandicap;
    }
  }
  
  return total;
};

/**
 * 참가자 평균 점수 계산 함수
 * @param {Object} participant - 참가자 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Number} - 참가자의 평균 점수
 */
export const calculateParticipantAverageScore = (participant, scoresProxy, gameCount) => {
  if (!participant || !participant.participantId) return 0;
  
  let total = 0;
  let playedGames = 0;
  const handicap = Number(participant.handicap) || 0;
  
  // 각 게임별 점수 합산 및 플레이한 게임 수 카운트
  for (let i = 1; i <= gameCount; i++) {
    const scoreKey = `${participant.participantId}-${i}`;
    const score = scoresProxy[scoreKey];
    
    if (score !== undefined && score !== null && score !== '') {
      total += Number(score) + handicap;
      playedGames++;
    }
  }
  
  return playedGames > 0 ? Math.round(total / playedGames) : 0;
};

/**
 * 개인전 순위 계산 함수
 * @param {Array} participants - 참가자 배열
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Object} - 참가자 ID를 키로, 순위를 값으로 하는 객체
 */
export const calculateIndividualRankings = (participants, scoresProxy, gameCount) => {
  if (!participants || participants.length === 0) return {};
  
  // 참가자별 총점 계산
  const participantsWithScores = participants.map(participant => ({
    participantId: participant.participantId,
    name: participant.name,
    totalScore: calculateParticipantTotalScore(participant, scoresProxy, gameCount),
    // 동점자 처리를 위한 추가 정보
    highestGame: getHighestGameScore(participant, scoresProxy, gameCount),
    handicap: Number(participant.handicap) || 0,
    scoreDeviation: getScoreDeviation(participant, scoresProxy, gameCount),
    birthday: participant.birthday ? new Date(participant.birthday) : new Date('9999-12-31')
  }));
  
  // 정렬 기준 적용
  // 1. 총점 내림차순
  // 2. 동점시 핸디캡이 낮은 순
  // 3. 핸디캡도 같으면 점수 편차가 적은 순
  // 4. 점수 편차도 같으면 생년월일이 빠른 순
  participantsWithScores.sort((a, b) => {
    // 1. 총점 비교
    if (b.totalScore !== a.totalScore) {
      return b.totalScore - a.totalScore;
    }
    
    // 2. 핸디캡 비교 (낮은 순)
    if (a.handicap !== b.handicap) {
      return a.handicap - b.handicap;
    }
    
    // 3. 점수 편차 비교 (적은 순)
    if (a.scoreDeviation !== b.scoreDeviation) {
      return a.scoreDeviation - b.scoreDeviation;
    }
    
    // 4. 생년월일 비교 (빠른 순)
    return a.birthday - b.birthday;
  });
  
  // 동점자 비교 함수 - 모든 기준을 적용하여 동점자 판별
  const compareParticipants = (a, b) => {
    // 총점, 핸디캡, 점수 편차, 생년월일이 모두 같을 때만 동점으로 처리
    return a.totalScore === b.totalScore && 
           a.handicap === b.handicap && 
           a.scoreDeviation === b.scoreDeviation && 
           a.birthday.getTime() === b.birthday.getTime();
  };
  
  // assignRanks 함수를 사용하여 순위 부여 (동점자 처리 포함)
  return assignRanks(participantsWithScores, 'participantId', compareParticipants);
};

/**
 * 팀전 순위 계산 함수
 * @param {Array} teams - 팀 배열
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Object} - 팀 ID를 키로, 순위를 값으로 하는 객체
 */
export const calculateTeamRankings = (teams, scoresProxy, gameCount) => {
  if (!teams || teams.length === 0) return {};
  
  // 팀별 총점 계산
  const teamsWithScores = teams.map(team => {
    let teamTotalScore = 0;
    
    // 팀원들의 점수 합산
    if (team.members && team.members.length > 0) {
      team.members.forEach(member => {
        teamTotalScore += calculateParticipantTotalScore(member, scoresProxy, gameCount);
      });
    }
    
    return {
      teamId: team.id || team.teamNumber,
      teamNumber: team.teamNumber,
      totalScore: teamTotalScore,
      // 추후 동점자 처리를 위한 추가 정보
      memberCount: team.members ? team.members.length : 0,
      teamHandicap: Number(team.handicap) || 0
    };
  });
  
  // 총점 기준 내림차순 정렬
  teamsWithScores.sort((a, b) => b.totalScore - a.totalScore);
  
  // 순위 맵 생성
  const rankMap = {};
  teamsWithScores.forEach((team, index) => {
    if (team.teamId) {
      rankMap[team.teamId] = index + 1;
    }
  });
  
  return rankMap;
};

/**
 * 게임별 순위 계산 함수
 * @param {Array} participants - 참가자 배열
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameNumber - 게임 번호
 * @returns {Object} - 참가자 ID를 키로, 해당 게임의 순위를 값으로 하는 객체
 */
export const calculateGameRankings = (participants, scoresProxy, gameNumber) => {
  if (!participants || participants.length === 0 || !gameNumber) return {};
  
  // 참가자별 해당 게임 점수 계산
  const participantsWithGameScore = participants.map(participant => {
    const scoreKey = `${participant.participantId}-${gameNumber}`;
    const score = scoresProxy[scoreKey];
    const handicap = Number(participant.handicap) || 0;
    
    let gameScore = 0;
    if (score !== undefined && score !== null && score !== '') {
      gameScore = Number(score) + handicap;
    }
    
    return {
      participantId: participant.participantId,
      name: participant.name,
      gameScore: gameScore,
      handicap: handicap
    };
  });
  
  // 게임 점수 기준 내림차순 정렬
  participantsWithGameScore.sort((a, b) => b.gameScore - a.gameScore);
  
  // 동점자 비교 함수 - 게임 점수가 같은 경우 동점으로 처리
  const compareParticipants = (a, b) => {
    return a.gameScore === b.gameScore;
  };
  
  // assignRanks 함수를 사용하여 순위 부여 (동점자 처리 포함)
  return assignRanks(participantsWithGameScore, 'participantId', compareParticipants);
};

/**
 * 참가자의 최고 게임 점수 구하기
 * @param {Object} participant - 참가자 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Number} - 최고 게임 점수
 */
export const getHighestGameScore = (participant, scoresProxy, gameCount) => {
  if (!participant || !participant.participantId) return 0;
  
  let highestScore = 0;
  const handicap = Number(participant.handicap) || 0;
  
  for (let i = 1; i <= gameCount; i++) {
    const scoreKey = `${participant.participantId}-${i}`;
    const score = scoresProxy[scoreKey];
    
    if (score !== undefined && score !== null && score !== '') {
      const gameScore = Number(score) + handicap;
      if (gameScore > highestScore) {
        highestScore = gameScore;
      }
    }
  }
  
  return highestScore;
};

/**
 * 참가자의 최저 게임 점수 구하기
 * @param {Object} participant - 참가자 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Number} - 최저 게임 점수
 */
export const getLowestGameScore = (participant, scoresProxy, gameCount) => {
  if (!participant || !participant.participantId) return 0;
  
  let lowestScore = Number.MAX_SAFE_INTEGER;
  const handicap = Number(participant.handicap) || 0;
  let hasValidScore = false;
  
  for (let i = 1; i <= gameCount; i++) {
    const scoreKey = `${participant.participantId}-${i}`;
    const score = scoresProxy[scoreKey];
    
    if (score !== undefined && score !== null && score !== '') {
      const gameScore = Number(score) + handicap;
      if (gameScore < lowestScore) {
        lowestScore = gameScore;
        hasValidScore = true;
      }
    }
  }
  
  return hasValidScore ? lowestScore : 0;
};

/**
 * 참가자의 게임 점수 편차 계산
 * @param {Object} participant - 참가자 객체
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Number} - 점수 편차 (최고 점수 - 최저 점수)
 */
export const getScoreDeviation = (participant, scoresProxy, gameCount) => {
  const highestScore = getHighestGameScore(participant, scoresProxy, gameCount);
  const lowestScore = getLowestGameScore(participant, scoresProxy, gameCount);
  
  return highestScore - lowestScore;
};

/**
 * 순위 부여 함수 - 동점자 처리 포함
 * @param {Array} items - 정렬된 아이템 배열
 * @param {String} idKey - 아이템의 고유 ID를 나타내는 키 이름
 * @param {Function} compareFunc - 두 아이템이 동점인지 비교하는 함수 (a, b) => boolean
 * @returns {Object} - 아이템 ID를 키로, 순위를 값으로 하는 객체
 */
export const assignRanks = (items, idKey, compareFunc) => {
  if (!items || items.length === 0) return {};
  
  const rankMap = {};
  
  // 예외 처리: 아이템이 하나만 있는 경우
  if (items.length === 1 && items[0][idKey]) {
    rankMap[items[0][idKey]] = 1;
    return rankMap;
  }
  
  // 동점자 그룹 처리
  const groups = [];
  let currentGroup = [];
  
  // 첫 번째 아이템 처리
  if (items[0][idKey]) {
    currentGroup.push(items[0]);
  }
  
  // 동점자 그룹화
  for (let i = 1; i < items.length; i++) {
    const current = items[i];
    const prev = items[i-1];
    
    // 아이템 ID가 없는 경우 건너뛰기
    if (!current[idKey]) continue;
    
    // 동점 여부 확인
    if (compareFunc(current, prev)) {
      // 동점자는 현재 그룹에 추가
      currentGroup.push(current);
    } else {
      // 동점이 아니면 현재 그룹 저장하고 새 그룹 시작
      if (currentGroup.length > 0) {
        groups.push(currentGroup);
      }
      currentGroup = [current];
    }
  }
  
  // 마지막 그룹 추가
  if (currentGroup.length > 0) {
    groups.push(currentGroup);
  }
  
  // 그룹별 순위 부여
  let nextRank = 1;
  
  for (const group of groups) {
    // 현재 그룹의 모든 아이템에 동일한 순위 부여
    for (const item of group) {
      if (item[idKey]) {
        rankMap[item[idKey]] = nextRank;
      }
    }
    
    // 다음 순위는 현재 그룹 크기를 더한 값
    nextRank += group.length;
  }
  
  return rankMap;
};

/**
 * 순위 색상 클래스 결정 함수
 * @param {Number} rank - 순위
 * @returns {String} - 순위에 따른 CSS 클래스 이름
 */
export const getRankColorClass = (rank) => {
  if (!rank || rank <= 0) return 'rank-other';
  
  if (rank <= 5) {
    return `rank-${rank}`;
  }
  
  return 'rank-other';
};

/**
 * 팀 전체 순위 계산 함수
 * @param {Array} teams - 팀 배열
 * @param {Object} scoresProxy - 점수 프록시 객체
 * @param {Number} gameCount - 게임 수
 * @returns {Object} - 팀 ID를 키로, 순위를 값으로 하는 객체
 */
export const calculateTeamOverallRankings = (teams, scoresProxy, gameCount) => {
  if (!teams || teams.length === 0) return {};
  
  // 팀별 총점 계산
  const teamTotals = teams.map(team => {
    // 각 게임별 점수 합산
    let totalScore = 0;
    
    // 팀의 게임별 점수 및 편차 계산을 위한 배열
    const gameScores = [];
    
    for (let i = 1; i <= gameCount; i++) {
      const gameScore = calculateTeamGameScore(team, scoresProxy, i);
      totalScore += gameScore;
      gameScores.push(gameScore);
    }
    
    // 팀 점수 편차 계산 (최고 점수 - 최저 점수)
    let scoreDeviation = 0;
    if (gameScores.length > 0) {
      const maxScore = Math.max(...gameScores.filter(score => score > 0));
      const minScore = Math.min(...gameScores.filter(score => score > 0));
      scoreDeviation = maxScore - minScore;
    }
    
    // 팀원들의 평균 생년월일 계산
    let averageBirthday = new Date('9999-12-31');
    if (team.members && team.members.length > 0) {
      const validBirthdays = team.members
        .filter(member => member.birthday)
        .map(member => new Date(member.birthday));
      
      if (validBirthdays.length > 0) {
        // 평균 샜산을 위해 총 밀리초 계산
        const totalMs = validBirthdays.reduce((sum, date) => sum + date.getTime(), 0);
        averageBirthday = new Date(totalMs / validBirthdays.length);
      }
    }
    
    return {
      teamId: team.id || team.teamNumber,
      totalScore: totalScore,
      handicapSum: calculateTeamTotalHandicap(team),
      memberCount: (team.members ? team.members.length : 0),
      scoreDeviation: scoreDeviation,
      averageBirthday: averageBirthday
    };
  });
  
  // 정렬 기준 적용
  // 1. 총점 내림차순
  // 2. 동점시 핸디캡이 낮은 순
  // 3. 핸디캡도 같으면 점수 편차가 적은 순
  // 4. 점수 편차도 같으면 생년월일 평균이 빠른 순
  teamTotals.sort((a, b) => {
    // 1. 총점 비교
    if (b.totalScore !== a.totalScore) return b.totalScore - a.totalScore;
    
    // 2. 동점시 핸디캡이 적은 팀이 순위가 높음
    if (a.handicapSum !== b.handicapSum) return a.handicapSum - b.handicapSum;
    
    // 3. 핸디캡도 같으면 점수 편차가 적은 팀이 순위가 높음
    if (a.scoreDeviation !== b.scoreDeviation) return a.scoreDeviation - b.scoreDeviation;
    
    // 4. 점수 편차도 같으면 팀원들의 평균 생년월일이 빠른 팀이 순위가 높음
    return a.averageBirthday - b.averageBirthday;
  });
  
  // 동점자 비교 함수 - 모든 기준을 적용하여 동점자 판별
  const compareTeams = (a, b) => {
    // 총점, 핸디캡 합계, 점수 편차, 평균 생년월일이 모두 같을 때만 동점으로 처리
    return a.totalScore === b.totalScore && 
           a.handicapSum === b.handicapSum && 
           a.scoreDeviation === b.scoreDeviation && 
           a.averageBirthday.getTime() === b.averageBirthday.getTime();
  };
  
  // assignRanks 함수를 사용하여 순위 부여 (동점자 처리 포함)
  return assignRanks(teamTotals, 'teamId', compareTeams);
};
