<commit_before>
import {handleActions} from 'redux-actions'
import {createStructuredSelector} from 'reselect'

import invariant from 'invariant'
import {indexBy, where, sortBy, omit, pluck, filter} from 'underline'

const initialState = {
  tasks: {},
  finishedTasks: [],
  downloads: {},
  downloadsPaused: false
}

const uninstall = (state, action) => {
  const {downloads} = state
  const newDownloads = downloads::filter((x) => x.gameId !== action.gameId)::indexBy('id')
  return {...state, downloads: newDownloads}
}

const updateSingle = (state, action, record) => {
  const {downloads} = state
  const {id} = record
  invariant(id, 'valid download id in progress')
  const download = downloads[id]
  invariant(id, 'valid download being updated')
  const newDownloads = {
    ...downloads,
    [id]: {
      ...download,
      ...record
    }
  }::indexBy('id')
  return {...state, downloads: newDownloads}
}

const reducer = handleActions({
  QUEUE_CAVE_UNINSTALL: uninstall,
  QUEUE_CAVE_REINSTALL: uninstall,

  TASK_STARTED: (state, action) => {
    const {tasks} = state
    const task = action.payload
    invariant(task.id, 'valid task id in started')
    const newTasks = {...tasks, [task.id]: task}
    return {...state, tasks: newTasks}
  },

  TASK_PROGRESS: (state, action) => {
    const {tasks} = state
    const record = action.payload
    const {id} = record
    invariant(id, 'valid task id in progress')
    const task = tasks[id]
    const newTasks = {...tasks, [id]: {...task, ...record}}
    return {...state, tasks: newTasks}
  },

  TASK_ENDED: (state, action) => {
    const {name, err, taskOpts, id} = action.payload
    invariant(id, 'valid task id in ended')
    const {tasks, finishedTasks} = state
    const newTasks = tasks::omit(id)
    const newFinishedTasks = [tasks[id], ...finishedTasks]

    let newDownloads = state.downloads
    if (name === 'uninstall' && !err) {
      newDownloads = newDownloads::filter((x) => x.gameId !== taskOpts.gameId)
    }

    return {...state, tasks: newTasks, finishedTasks: newFinishedTasks, downloads: newDownloads}
  },

  /* ************************************************* */
  /*                    Woo downloads                  */
  /* ************************************************* */

  DOWNLOAD_STARTED: (state, action) => {
    const {downloads} = state
    const download = action.payload
    invariant(download.id, 'valid download id in started')
    const carryOver = downloads::filter((x) => x.gameId !== download.gameId)::indexBy('id')
    const newDownloads = {...carryOver, [download.id]: download}
    return {...state, downloads: newDownloads}
  },

  DOWNLOAD_PROGRESS: (state, action) => {<commit_msg>:bug: Fix download state corruption<commit_after>
import {handleActions} from 'redux-actions'
import {createStructuredSelector} from 'reselect'

import invariant from 'invariant'
import {indexBy, where, sortBy, omit, pluck, filter} from 'underline'

const initialState = {
  tasks: {},
  finishedTasks: [],
  downloads: {},
  downloadsPaused: false
}

const uninstall = (state, action) => {
  const {downloads} = state
  const newDownloads = downloads::filter((x) => x.gameId !== action.gameId)::indexBy('id')
  return {...state, downloads: newDownloads}
}

const updateSingle = (state, action, record) => {
  const {downloads} = state
  const {id} = record
  invariant(id, 'valid download id in progress')
  const download = downloads[id]
  invariant(id, 'valid download being updated')
  const newDownloads = {
    ...downloads,
    [id]: {
      ...download,
      ...record
    }
  }
  return {...state, downloads: newDownloads}
}

const reducer = handleActions({
  QUEUE_CAVE_UNINSTALL: uninstall,
  QUEUE_CAVE_REINSTALL: uninstall,

  TASK_STARTED: (state, action) => {
    const {tasks} = state
    const task = action.payload
    invariant(task.id, 'valid task id in started')
    const newTasks = {...tasks, [task.id]: task}
    return {...state, tasks: newTasks}
  },

  TASK_PROGRESS: (state, action) => {
    const {tasks} = state
    const record = action.payload
    const {id} = record
    invariant(id, 'valid task id in progress')
    const task = tasks[id]
    const newTasks = {...tasks, [id]: {...task, ...record}}
    return {...state, tasks: newTasks}
  },

  TASK_ENDED: (state, action) => {
    const {name, err, taskOpts, id} = action.payload
    invariant(id, 'valid task id in ended')
    const {tasks, finishedTasks} = state
    const newTasks = tasks::omit(id)
    const newFinishedTasks = [tasks[id], ...finishedTasks]

    let newDownloads = state.downloads
    if (name === 'uninstall' && !err) {
      newDownloads = newDownloads::filter((x) => x.gameId !== taskOpts.gameId)::indexBy('id')
    }

    return {...state, tasks: newTasks, finishedTasks: newFinishedTasks, downloads: newDownloads}
  },

  /* ************************************************* */
  /*                    Woo downloads                  */
  /* ************************************************* */

  DOWNLOAD_STARTED: (state, action) => {
    const {downloads} = state
    const download = action.payload
    invariant(download.id, 'valid download id in started')
    const carryOver = downloads::filter((x) => x.gameId !== download.gameId)::indexBy('id')
    const newDownloads = {...carryOver, [download.id]: download}
    return {...state, downloads: newDownloads}
  },

  DOWNLOAD_PROGRESS: (state, action) => {
{'fraction_non_alphanumeric': 0.17943994104642594, 'fraction_numerical': 0.0, 'mean_word_length': 3.453650533223954, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 71, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6309835', 'n_tokens_mistral': 1708, 'n_tokens_neox': 1651, 'n_words': 447}