
import { FormButton, LinkButton } from './Button';
import { createContext, Fragment } from 'preact';
import { usePopup } from './usePopup';
import { useCallback, useContext } from 'preact/hooks';
import { ExportFormat, exportFormatToString } from '../rolltable';
import {
	GeneratedElement,
	type GeneratedElementProps,
	reconstituteGeneratedElement,
} from './GeneratedElement';
import { IncludesResponses } from './ResponsesPage';
import { tableIdentifier } from './TableHeader';

export const IncludesGenerator = createContext(false)

export interface GeneratorProps {
	generatorTargetUrl: string
	elements: GeneratedElementProps[]
	addToDiscordUrl: string|null
	editable: boolean
}

export enum GeneratorSelect {
	All = "all",
	None = "none",
}

export enum GeneratorReroll {
	All = "all",
	Selected = "selected",
}

export function reconstituteGenerator(element: HTMLDivElement, partial?: Partial<GeneratorProps>): GeneratorProps {
	const addToDiscordUrl = partial?.addToDiscordUrl ?? element.querySelector<HTMLAnchorElement>("#addToDiscord")?.href ?? null
	const editable = partial?.editable ?? !!element.querySelector("#rollButtons")
	const elements = partial?.elements ??
		Array.from(element.querySelector<HTMLUListElement>("#generatedScenario")!.children)
			.map(li => reconstituteGeneratedElement(li as HTMLLIElement, editable ? {} : {selected: null}))

	const generatorTargetUrl = partial?.generatorTargetUrl ?? element.querySelector<HTMLFormElement>("#generatorWindow")!.action
	return {
		addToDiscordUrl,
		editable,
		generatorTargetUrl,
		elements: elements,
	}
}

export interface GeneratorEvents {
	onCopy?: (format: ExportFormat) => Promise<void>
	onReroll?: (which: GeneratorReroll) => Promise<void>
	onSelect?: (which: GeneratorSelect) => void
	onSelectionChange?: (tableId: number, selected: boolean) => void
}

enum GeneratorSelectionState {
	All = "All",
	Partial = "Some",
	None = "None"
}

export function GeneratorPage({ editable, generatorTargetUrl, addToDiscordUrl, onSelectionChange, onSelect, onReroll, onCopy, elements }: GeneratorProps & GeneratorEvents) {
	const includesResponses = useContext(IncludesResponses);
	const [copyPopupHost, showCopyPopup] = usePopup<HTMLDivElement>()
	const [rerollPopupHost, showRerollPopup] = usePopup<HTMLDivElement>()
	const copyWrapper = useCallback((format: ExportFormat) => {
		if (!onCopy) {
			console.error("No copy handler")
			return showCopyPopup(`Failed to copy ${exportFormatToString(format)} to clipboard`, 'error')
		}
		onCopy(format).then(() => {
			return showCopyPopup(`Copied ${exportFormatToString(format)} to clipboard`)
		}).catch((ex: unknown) => {
			console.error(ex)
			return showCopyPopup(`Failed to copy ${exportFormatToString(format)} to clipboard`, 'error')
		}).catch((ex: unknown) => {
			console.error(ex)
		})
	}, [showCopyPopup, onCopy])
	const md = useCallback(() => copyWrapper(ExportFormat.Markdown), [copyWrapper])
	const bb = useCallback(() => copyWrapper(ExportFormat.BBCode), [copyWrapper])
	const emoji = useCallback(() => copyWrapper(ExportFormat.TextEmoji), [copyWrapper])
	const text = useCallback(() => copyWrapper(ExportFormat.TextOnly), [copyWrapper])
	const selected = elements.reduce<null|GeneratorSelectionState>((current, next) => {
		if (next.selected === null) {
			return current
		}
		switch (current) {
			case GeneratorSelectionState.Partial:
				return GeneratorSelectionState.Partial
			case GeneratorSelectionState.None:
				return next.selected ? GeneratorSelectionState.Partial : GeneratorSelectionState.None
			case GeneratorSelectionState.All:
				return next.selected ? GeneratorSelectionState.All : GeneratorSelectionState.Partial
			case null:
				return next.selected ? GeneratorSelectionState.All : GeneratorSelectionState.None
		}
	}, null)
	const selectAll = useCallback((ev: Event) => {
			if (!onSelect || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) {
				return
			}
			onSelect(GeneratorSelect.All)
	}, [onSelect, showRerollPopup])
	const selectNone = useCallback((ev: Event) => {
		if (!onSelect || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) {
			return
		}
		onSelect(GeneratorSelect.None)
	}, [onSelect, showRerollPopup])
	const rerollSelected = useCallback((ev: Event) => {
		if (!onReroll || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) {
			return
		}
		onReroll(GeneratorReroll.Selected).then(() => {}).catch((ex: unknown) => {
			console.error(ex)
			return showRerollPopup(`Failed to reroll`, 'error')
		}).catch((ex: unknown) => {
			console.error(ex)
		})
	}, [onReroll, showRerollPopup])
	const rerollAll = useCallback((ev: Event) => {
		if (!onReroll || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) {
			return
		}
		onReroll(GeneratorReroll.All).then(() => {}).catch((ex: unknown) => {
			console.error(ex)
			return showRerollPopup(`Failed to reroll all`, 'error')
		}).catch((ex: unknown) => {
			console.error(ex)
		})
	}, [onReroll, showRerollPopup])

	return <div id="generator" class="page">
		<form method="post" action={generatorTargetUrl} id="generatorWindow" class="window readable">
			<h2 id="generatorHead">Your generated scenario</h2>
			<ul id="generatedScenario">
				{elements.map(i => <GeneratedElement key={tableIdentifier(i.table)} {...i} onSelectionChange={onSelectionChange} />)}
			</ul>
			<div id="generatorControls">
				<div ref={copyPopupHost} id="copyButtons" className="buttons requiresJs jsPopupHost">
					<FormButton id="copyMD" type="button" onClick={onCopy && md} disabled={!onCopy}>Markdown</FormButton>
					<FormButton id="copyBB" type="button" onClick={onCopy && bb} disabled={!onCopy}>BBCode</FormButton>
					<FormButton id="copyEmojiText" type="button" onClick={onCopy && emoji} disabled={!onCopy}>Text + Emoji</FormButton>
					<FormButton id="copyText" type="button" onClick={onCopy && text} disabled={!onCopy}>Text Only</FormButton>
				</div>
				{editable ? <div ref={rerollPopupHost} id="rollButtons" class="buttons jsPopupHost">
					<FormButton type="submit" id="reroll" name="submit"
											value="reroll" disabled={onReroll && (!selected || selected === GeneratorSelectionState.None)} onClick={onReroll && rerollSelected}>
						Reroll {selected === GeneratorSelectionState.All ? 'All' : 'Selected'}
					</FormButton>
					<FormButton type="button" id="selectAll" class="requiresJs" onClick={selectAll} disabled={!onSelect || selected === GeneratorSelectionState.All}>Select All</FormButton>
					<FormButton type="button" id="selectNone" class="requiresJs" onClick={selectNone} disabled={!onSelect || !selected || selected === GeneratorSelectionState.None}>Select None</FormButton>
				</div> : null}
				<div id="scenarioButtons" class="buttons">
					{editable ? <Fragment>
						<LinkButton id="rerollAll" href={generatorTargetUrl} external={false} onClick={onReroll && rerollAll}>New Scenario</LinkButton>
						<FormButton id="saveScenario" name="submit" value="saveScenario" type="submit">Get Scenario Link</FormButton>
					</Fragment> : <Fragment>
						<LinkButton id="openInGenerator" href={generatorTargetUrl} external={false}>Open in Generator</LinkButton>
					</Fragment>}
				</div>
				{ addToDiscordUrl || includesResponses ?
					<div id="generatorLinks" class="buttons">
						{addToDiscordUrl && <LinkButton external={true} id="addToDiscord" href={addToDiscordUrl}>Add to Discord</LinkButton>}
						{includesResponses ? <LinkButton external={false} id="goToResponses" href="#responses">View Possible Responses</LinkButton> : null}
					</div> : null}
			</div>
		</form>
	</div>
}
