import { GeneratorPage, GeneratorSelect, IncludesGenerator } from './GeneratorPage';
import { PageFooter } from './PageFooter';
import type { GeneratedElementProps } from './GeneratedElement';
import { useCallback, useMemo, useState } from 'preact/hooks';
import { ExportFormat, exportScenario, RollSelections, type RollTable, type RollTableResult } from '../rolltable';

export interface GeneratorMainProps {
	editable: boolean

	generatorTargetUrl: string
	addToDiscordUrl: string
	creditsUrl: string

	initialResults: ReadonlyMap<RollTable, RollTableResult>
	initialSelected?: ReadonlySet<RollTable>
}

export interface GeneratorMainEvents {
	copyText?: (text: string) => Promise<void>
}

// TODO: add a "reconstitute" function for MainGeneratorOnly
// TODO: add the other two top-level pages (MainResponsesOnly, MainGeneratorResponses) with "reconstitute" functions
// TODO: add the entry points that reconstitute and hydrate each of the respective top-level pages

function MainGeneratorOnly({
				 editable, generatorTargetUrl, addToDiscordUrl,
				 creditsUrl, initialResults, initialSelected, copyText}: GeneratorMainProps & GeneratorMainEvents) {
	const [results, ] =
		useState<ReadonlyMap<RollTable, RollTableResult>>(initialResults)
	const [selected, setSelected] =
		useState<ReadonlySet<RollTable>|null>(initialSelected ?? null)
	const onCopy = useCallback(async (format: ExportFormat) => {
		if (!copyText) {
			return Promise.reject(Error("Copy functionality is not implemented"))
		}
		return copyText(exportScenario(Array.from(results.values()), format))
	}, [copyText, results])
	const onSelectionChange = useCallback((tableId: number, state: boolean) => {
		const table = Array.from(initialResults.keys()).find(table => table.full && table.id === tableId)
		if (!table) {
			return
		}
		const newSelection = new RollSelections(selected)
		if (state) {
			newSelection.add(table)
		} else {
			newSelection.delete(table)
		}
		setSelected(newSelection)
	}, [initialResults, selected, setSelected])
	const onSelect = useCallback((select: GeneratorSelect) => {
		switch (select) {
			case GeneratorSelect.All:
				setSelected(new RollSelections(initialResults.keys()));
				break;
			case GeneratorSelect.None:
				setSelected(new RollSelections());
				break;
		}
	}, [initialResults, setSelected])
	const elements = useMemo(() => {
		const output: GeneratedElementProps[] = []
		for (const result of results.values()) {
			if (result.full) {
				output.push({
					...result,
					selected: selected === null ? null : selected.has(result.table)
				})
			} else {
				output.push({
					...result,
					selected: null,
				})
			}
		}
		return output
	}, [results, selected])
	return <IncludesGenerator.Provider value={true}>
		<GeneratorPage
			generatorTargetUrl={generatorTargetUrl}
			elements={elements}
			addToDiscordUrl={addToDiscordUrl}
			editable={editable}
		  onCopy={onCopy}
			// TODO: implement onReroll using JSON fetch
			// specifically: POST to the target URL as if you're submitting the form,
			// _but_ add Accept: text/json to indicate you want it for API purposes and not as a page
		  onSelect={selected ? onSelect : undefined}
		  onSelectionChange={selected ? onSelectionChange : undefined} />
		<PageFooter creditsUrl={creditsUrl} />
	</IncludesGenerator.Provider>
}
