const RUNNING_STATE = 0
const SUCCESS_STATE = 1
const FAILED_STATE = -1

function toNumber(value) {
	if (value === '' || value === null || value === undefined) return undefined
	const numeric = Number(value)
	return Number.isNaN(numeric) ? undefined : numeric
}

function pickReportId(source) {
	if (source === null || source === undefined) return undefined
	if (typeof source === 'number') return source
	if (typeof source === 'string') {
		const numeric = toNumber(source)
		return numeric === undefined ? undefined : numeric
	}
	if (typeof source !== 'object') return undefined
	const direct = toNumber(source.reportId ?? source.id)
	if (direct !== undefined) return direct
	for (const key of ['data', 'dto', 'info']) {
		const nested = pickReportId(source[key])
		if (nested !== undefined) return nested
	}
	return undefined
}

function extractReportId(payload) {
	return pickReportId(payload)
}

function normalizeGenerationStatus(payload = {}) {
	const source = payload && typeof payload === 'object' ? payload : {}
	const state = toNumber(source.state)
	return {
		reportId: extractReportId(source) ?? '',
		state: state === undefined ? RUNNING_STATE : state,
		status: source.status || '',
		errorMessage: source.errorMessage || ''
	}
}

function applyGenerationStatus(payload = {}) {
	const generation = normalizeGenerationStatus(payload)
	if (generation.state === FAILED_STATE) {
		return {
			...generation,
			title: '报告生成失败',
			subtitle: '',
			description: generation.errorMessage || '失败原因：网络延迟',
			errorMessage: generation.errorMessage || '网络延迟',
			polling: false,
			actionText: '重新生成',
			imageKey: 'fail'
		}
	}
	if (generation.state === SUCCESS_STATE) {
		return {
			...generation,
			title: '报告生成成功',
			subtitle: '',
			description: '报告已生成完成，你可以去我的PREILL报告查阅报告结果。',
			errorMessage: '',
			polling: false,
			actionText: '返回',
			imageKey: 'success'
		}
	}
	return {
		...generation,
		title: '报告正在生成中~',
		subtitle: '预计所需时间1小时左右',
		description: '我们会在报告生成完成后提示你，你可以去我的PREILL报告查阅报告结果。',
		errorMessage: '',
		polling: true,
		actionText: '返回',
		imageKey: 'success'
	}
}

function replaceFirstPage(currentList, nextList) {
	void currentList
	return Array.isArray(nextList) ? nextList.slice() : []
}

function shouldResumePolling(reportId, generation = {}) {
	return Boolean(reportId && normalizeGenerationStatus(generation).state === RUNNING_STATE)
}

function reconcileStatusQueryError(currentGeneration = {}) {
	return applyGenerationStatus(normalizeGenerationStatus(currentGeneration))
}

function createStatusRequestState() {
	return {
		isPageVisible: false,
		statusVisibilityToken: 0,
		statusRequestSeq: 0,
		statusActiveRequestId: 0,
		statusRequestInFlight: false
	}
}

function setStatusPageVisible(state, visible) {
	if (!state || state.isPageVisible === visible) return state ? state.statusVisibilityToken : 0
	state.isPageVisible = visible
	if (!visible) {
		state.statusVisibilityToken += 1
		state.statusActiveRequestId = 0
		state.statusRequestInFlight = false
	}
	return state.statusVisibilityToken
}

function beginStatusRequest(state) {
	if (!state || !state.isPageVisible || state.statusRequestInFlight) return null
	state.statusRequestSeq += 1
	state.statusActiveRequestId = state.statusRequestSeq
	state.statusRequestInFlight = true
	return {
		requestId: state.statusActiveRequestId,
		visibilityToken: state.statusVisibilityToken
	}
}

function shouldApplyStatusResponse(state, meta) {
	return Boolean(
		state
		&& meta
		&& state.isPageVisible
		&& state.statusRequestInFlight
		&& state.statusActiveRequestId === meta.requestId
		&& state.statusVisibilityToken === meta.visibilityToken
	)
}

function finishStatusRequest(state, meta) {
	if (!state || !meta) return
	if (state.statusActiveRequestId === meta.requestId) {
		state.statusActiveRequestId = 0
		state.statusRequestInFlight = false
	}
}

function createListRefreshState() {
	return {
		refreshGeneration: 0,
		inFlightPageRequests: {}
	}
}

function beginListRefresh(state) {
	if (!state) return 0
	state.refreshGeneration += 1
	return state.refreshGeneration
}

function createListRequestMeta(generation, page) {
	return { generation, page }
}

function shouldApplyListResponse(currentGeneration, meta) {
	return Boolean(meta && currentGeneration === meta.generation)
}

function beginListPageRequest(state, generation, page) {
	if (!state) return null
	const key = `${generation}:${page}`
	if (state.inFlightPageRequests[key]) return null
	const meta = { generation, page, key }
	state.inFlightPageRequests[key] = true
	return meta
}

function finishListPageRequest(state, meta) {
	if (!state || !meta || !meta.key) return
	delete state.inFlightPageRequests[meta.key]
}

module.exports = {
	RUNNING_STATE,
	SUCCESS_STATE,
	FAILED_STATE,
	extractReportId,
	normalizeGenerationStatus,
	applyGenerationStatus,
	replaceFirstPage,
	shouldResumePolling,
	reconcileStatusQueryError,
	createStatusRequestState,
	setStatusPageVisible,
	beginStatusRequest,
	shouldApplyStatusResponse,
	finishStatusRequest,
	createListRefreshState,
	beginListRefresh,
	createListRequestMeta,
	shouldApplyListResponse,
	beginListPageRequest,
	finishListPageRequest
}
