import type {
  CourtSide,
  GroupTeam,
  MatchResultsRecord,
  PlayerSlot,
  ScoreState,
} from '../types'

const PLACEHOLDER_NAME = '輪空'
const TOTAL_GROUPS = 3

export function parseRoster(input: string) {
  const uniqueNames = new Set<string>()

  input
    .split(/[\n,，、]+/g)
    .map((name) => name.trim())
    .filter(Boolean)
    .forEach((name) => uniqueNames.add(name))

  return Array.from(uniqueNames)
}

export function buildManualGroups(areaA: string[], areaB: string[]) {
  const targetCount = Math.max(areaA.length, areaB.length)
  const shuffledA = shuffleList(areaA)
  const shuffledB = shuffleList(areaB)
  const paddedA = padTeams(shuffledA, targetCount)
  const paddedB = padTeams(shuffledB, targetCount)

  return Array.from({ length: TOTAL_GROUPS }, (_, roundIndex) => ({
    id: roundIndex + 1,
    teams: paddedA.map((playerA, index) =>
      createTeam(
        index + 1,
        playerA,
        paddedB[(index + roundIndex) % paddedB.length],
      ),
    ),
  }))
}

export function convertDbRecordToGroups(record: MatchResultsRecord) {
  const personnel = JSON.parse(record.personnel) as [number, string][]
  const battlecombination = JSON.parse(record.battlecombination ?? '{}') as Record<
    string,
    [string, string][]
  >

  const areaA = personnel.filter(([group]) => group === 1).map(([, name]) => name)
  const areaB = personnel.filter(([group]) => group === 0).map(([, name]) => name)

  const groups = Object.keys(battlecombination)
    .sort((left, right) => Number(left) - Number(right))
    .map((key, roundIndex) => ({
      id: roundIndex + 1,
      teams: battlecombination[key].map(([playerA, playerB], teamIndex) =>
        createTeam(teamIndex + 1, playerA, playerB),
      ),
    }))

  return { areaA, areaB, groups }
}

export function getTeamDisplayName(team: GroupTeam) {
  return `${team.playerA} / ${team.playerB}`
}

export function getWinnerName(
  leftTeamName: string,
  rightTeamName: string,
  scoreState: ScoreState,
) {
  return scoreState.scoreLeft >= scoreState.scoreRight ? leftTeamName : rightTeamName
}

export function formatDateInputValue() {
  const now = new Date()
  const year = now.getFullYear()
  const month = String(now.getMonth() + 1).padStart(2, '0')
  const day = String(now.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

export function convertDateToKey(dateValue: string) {
  const [year = '', month = '', day = ''] = dateValue.split('-')
  return `${year}${month}${day}`
}

export function getServiceCourt(score: number): CourtSide {
  return score % 2 === 0 ? 'right' : 'left'
}

export function getMirroredCourt(court: CourtSide): CourtSide {
  return court === 'right' ? 'left' : 'right'
}

export function getCourtAssignments(
  team: GroupTeam,
  rightCourtPlayer: PlayerSlot,
  mirrored = false,
) {
  const rightScreenCourt = mirrored ? getMirroredCourt('right') : 'right'
  const leftScreenCourt = mirrored ? getMirroredCourt('left') : 'left'

  return [
    {
      slot: 'playerA' as const,
      name: team.playerA,
      court: (rightCourtPlayer === 'playerA' ? rightScreenCourt : leftScreenCourt) as CourtSide,
    },
    {
      slot: 'playerB' as const,
      name: team.playerB,
      court: (rightCourtPlayer === 'playerB' ? rightScreenCourt : leftScreenCourt) as CourtSide,
    },
  ]
}

export function getPlayerOnCourt(
  team: GroupTeam,
  rightCourtPlayer: PlayerSlot,
  targetCourt: CourtSide,
) {
  const assignments = getCourtAssignments(team, rightCourtPlayer)
  return assignments.find((assignment) => assignment.court === targetCourt) ?? null
}

export function getServingPlayer(
  team: GroupTeam,
  rightCourtPlayer: PlayerSlot,
  score: number,
) {
  const serverSlot = getServiceCourt(score) === 'right'
    ? rightCourtPlayer
    : rightCourtPlayer === 'playerA'
      ? 'playerB'
      : 'playerA'

  return {
    slot: serverSlot,
    name: team[serverSlot],
    court: getServiceCourt(score),
  }
}

export function getReceivingPlayer(
  team: GroupTeam,
  rightCourtPlayer: PlayerSlot,
  servingScore: number,
) {
  const receiverSlot = getServiceCourt(servingScore) === 'right'
    ? rightCourtPlayer
    : rightCourtPlayer === 'playerA'
      ? 'playerB'
      : 'playerA'

  return {
    slot: receiverSlot,
    name: team[receiverSlot],
    court: getServiceCourt(servingScore),
  }
}

export function swapCourtPositions(rightCourtPlayer: PlayerSlot): PlayerSlot {
  return rightCourtPlayer === 'playerA' ? 'playerB' : 'playerA'
}

// 判斷目前比分是否已分出勝負（達標分、Deuce 領先 2 分、或 30 分上限）。
export function hasWonGame(state: ScoreState) {
  const leadingScore = Math.max(state.scoreLeft, state.scoreRight)
  const trailingScore = Math.min(state.scoreLeft, state.scoreRight)

  if (leadingScore < state.targetScore) {
    return false
  }

  if (leadingScore >= 30) {
    return true
  }

  if (trailingScore >= state.targetScore - 1) {
    return leadingScore - trailingScore >= 2
  }

  return true
}

function createTeam(id: number, playerA: string, playerB: string) {
  return {
    id,
    playerA,
    playerB,
    isPlaceholderA: playerA === PLACEHOLDER_NAME,
    isPlaceholderB: playerB === PLACEHOLDER_NAME,
  }
}

function padTeams(list: string[], targetCount: number) {
  const next = [...list]

  while (next.length < targetCount) {
    next.push(PLACEHOLDER_NAME)
  }

  return next
}

function shuffleList<T>(list: T[]) {
  const next = [...list]

  for (let index = next.length - 1; index > 0; index -= 1) {
    const swapIndex = Math.floor(Math.random() * (index + 1))
    ;[next[index], next[swapIndex]] = [next[swapIndex], next[index]]
  }

  return next
}
