import type { Candidate, Item, ReleasePreview } from '../types.js' export type ScanErrorKind = 'not_found' | 'no_discogs_token' | 'rate_limited' | 'server' export type ScanState = | { phase: 'scan' } | { phase: 'looking'; code: string } | { phase: 'candidates'; code: string; candidates: Candidate[] } | { phase: 'confirm' code: string | null candidate: Candidate preview: ReleasePreview | null matchAlbumId: number | null adding: boolean addError: string | null } | { phase: 'added'; item: Item } | { phase: 'error'; kind: ScanErrorKind; code: string | null } export const INITIAL_SCAN_STATE: ScanState = { phase: 'scan' } export type ScanAction = | { type: 'DETECT'; code: string } | { type: 'CANDIDATES'; code: string; candidates: Candidate[] } | { type: 'NOT_FOUND'; code: string } | { type: 'ERROR'; kind: ScanErrorKind; code: string | null } | { type: 'SELECT'; candidate: Candidate } | { type: 'PREVIEW'; preview: ReleasePreview } | { type: 'SET_MATCH'; albumId: number } | { type: 'CLEAR_MATCH' } | { type: 'ADD_START' } | { type: 'ADDED'; item: Item } | { type: 'ADD_ERROR'; message: string } | { type: 'RESET' } export function scanReducer(state: ScanState, action: ScanAction): ScanState { switch (action.type) { case 'DETECT': return state.phase === 'scan' ? { phase: 'looking', code: action.code } : state case 'CANDIDATES': return state.phase === 'looking' ? { phase: 'candidates', code: action.code, candidates: action.candidates } : state case 'NOT_FOUND': return state.phase === 'looking' ? { phase: 'error', kind: 'not_found', code: action.code } : state case 'ERROR': return state.phase === 'looking' || state.phase === 'candidates' || state.phase === 'confirm' ? { phase: 'error', kind: action.kind, code: action.code } : state case 'SELECT': return state.phase === 'candidates' ? { phase: 'confirm', code: state.code, candidate: action.candidate, preview: null, matchAlbumId: null, adding: false, addError: null, } : state case 'PREVIEW': return state.phase === 'confirm' ? { ...state, preview: action.preview } : state case 'SET_MATCH': return state.phase === 'confirm' ? { ...state, matchAlbumId: action.albumId } : state case 'CLEAR_MATCH': return state.phase === 'confirm' ? { ...state, matchAlbumId: null } : state case 'ADD_START': return state.phase === 'confirm' && state.preview ? { ...state, adding: true, addError: null } : state case 'ADDED': return state.phase === 'confirm' ? { phase: 'added', item: action.item } : state case 'ADD_ERROR': return state.phase === 'confirm' ? { ...state, adding: false, addError: action.message } : state case 'RESET': return INITIAL_SCAN_STATE } }