import { IBlock } from '../training/types'
import { calculateDuration } from '../training/utils'
import { IExerciseItem } from './types'

/**
 * Find the right exercise given a certain time.
 * @param exerciseList
 * @param time
 */
export function getPosition(exerciseList: IExerciseItem[], time: number) {
  const index = exerciseList.findIndex(
    exercise => time < exercise.offset + exercise.duration
  )

  const previousExercise = index >= 1 ? exerciseList[index - 1] : null
  const currentExercise = index >= 0 ? exerciseList[index] : null
  const nextExercise =
    index >= 0 && index < exerciseList.length - 1
      ? exerciseList[index + 1]
      : null
  const values = {
    currentExercise,
    nextExercise,
    previousExercise,
    exerciseTime: 0
  }
  if (currentExercise !== null) {
    values.exerciseTime = Math.max(time - currentExercise.offset, 0)
  }
  return values
}

/**
 * Takes a (nested) block of exercises and returns a flat array of exercises.
 * @param blocks
 * @param initialOffset - used for recursive application
 */
export function getExerciseList(
  blocks: IBlock[],
  initialOffset = 0,
  toplevelBlock: undefined | string = undefined
): IExerciseItem[] {
  let offset = initialOffset
  return blocks
    .map(block => {
      if (block.blocks) {
        const blockArray = []
        for (let i = 0; i < (block.repetitions || 1); i++) {
          const subBlocks = getExerciseList(
            block.blocks,
            offset,
            toplevelBlock || block.title
          )
          const lastItem = subBlocks[subBlocks.length - 1]
          offset = lastItem.offset + lastItem.duration
          if (block.rest) {
            if (lastItem.exercise === 'Rest') {
              lastItem.duration += block.rest
              offset += block.rest
            } else {
              subBlocks.push({
                exercise: 'Rest',
                toplevelBlock: toplevelBlock || block.title,
                duration: block.rest,
                offset
              })
              offset += block.rest
            }
          }
          blockArray.push(subBlocks)
        }
        return blockArray.flat()
      } else if (block.exercises) {
        const blockArray: IExerciseItem[] = []
        const newItem = {
          exercise: block.exercises
            .map(exercise =>
              exercise.repetitions > 1
                ? `${exercise.repetitions}x ${exercise.name}`
                : exercise.name
            )
            .join(' - '),
          duration: calculateDuration(block),
          video: block.video,
          description: block.description,
          toplevelBlock: toplevelBlock || block.title,
          offset
        }
        for (let i = 0; i < (block.repetitions || 1); i++) {
          blockArray.push({ ...newItem, offset })
          offset += newItem.duration
        }
        return blockArray.flat()
      }
    })
    .flat()
}

export function getTrainingTime(exercises: IExerciseItem[]) {
  return exercises.reduce(
    (accumulator, exercise) => accumulator + exercise.duration,
    0
  )
}

export function polarToCartesian(
  centerX: number,
  centerY: number,
  radius: number,
  angleInDegrees: number
) {
  const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0

  return {
    x: centerX + radius * Math.cos(angleInRadians),
    y: centerY + radius * Math.sin(angleInRadians)
  }
}

export function describeArc(
  x: number,
  y: number,
  radius: number,
  startAngle: number,
  endAngle: number
) {
  const start = polarToCartesian(x, y, radius, endAngle)
  const end = polarToCartesian(x, y, radius, startAngle)

  const largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1'

  const arcString = `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArcFlag} 0 ${end.x} ${end.y}`

  return arcString
}

export function limit(value: number, min: number, max: number) {
  return Math.min(Math.max(min, value), max)
}
