import type { CarReader } from '@ipld/car'
import type { Applog, PromiseType } from '@wovin/core'
import type { Component, JSX, ParentComponent, Resource } from 'solid-js'
import type { otherIcons } from '../../unocss.safelist'
import type { retrievePubDataWithExtras } from '../ipfs/store-sync'
import type { DivProps } from '../ui/utils-ui'
import { createTimer } from '@solid-primitives/timer'
import { A } from '@solidjs/router'
import { decodePubFromCar, isEncryptedApplog, queryAndMap, querySingleAndMap, ThreadInMemory } from '@wovin/core'
import { mapArrayToObj } from '@wovin/utils/types'
import { Logger } from 'besonders-logger'
import classNames from 'classnames'
import { partition, size, uniqueId } from 'lodash-es'
import { createEffect, createMemo, createResource, createSignal, For, mergeProps, onMount, Show, splitProps, Suspense } from 'solid-js'
import { Dynamic } from 'solid-js/web'
import { phosphorIcons } from '../../unocss.safelist'
import { initialized, setStorageError } from '../appInit'
import { useAgent } from '../data/agent/AgentState'
import { BlockVM } from '../data/VMs/BlockVM'
import { retrievePubToThread } from '../ipfs/retrievePubToThread'
import { getPubExtraInfo } from '../ipfs/store-sync'
import { DefaultCenter, DefaultFull, DefaultSmall } from '../types/unocss-utils'
import { getStorageIssues, isOnline, isStorageReachable } from '../ui/online-second'
import { useRawThread } from '../ui/reactive'
import {
	createAsyncButtonHandler,
	createAsyncMemo,
	explorerUrl,
	isColorDark,
	makeGlobalHover,
	mergeStyles,
	stopPropagation,
	stringToColor,
	svgElementToDataURL,
	useLocationNavigate,
} from '../ui/utils-ui'

const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO)

export const ShortID: Component<{ id: string, href?: string }> = (props) => {
	return (
		<Dynamic
			component={props.href ? A : 'span'}
			class={props.href ? 'a-unstyled underline' : ''}
			flex='inline items-center'
			href={props.href ?? undefined}
			target={props.href ? '_blank' : undefined}
		>
			{/* max-w-5 truncate */}
			<code title={props.id}>{props.id.slice(-7)}</code>
		</Dynamic>
	)
}

export const CopyableID: Component<{ id: string, label?: string, buttonSize?: string }> = (_props) => {
	const props = mergeProps({ buttonSize: '5' }, _props)
	return (
		<span flex='inline items-center' onClick={stopPropagation} my--2>
			<code p='y-2 r--1'>{props.id.slice(-7)}</code>
			{' '}
			{/* t-[2px]  */}
			<sl-copy-button
				class='copy-button-compact'
				value={props.id}
				copy-label={props.label ?? undefined}
			>
				<Iconify name='copy-light' size={props.buttonSize} slot='copy-icon' />
			</sl-copy-button>
		</span>
	)
}
export const Spinner: ParentComponent<{ size?: string, color?: string }> = (props) => {
	return (
		<div flex='~ col items-center'>
			<sl-spinner
				style={`${props.size ? `font-size: ${props.size}; ` : ''}${
					props.color ? `--indicator-color: ${props.color}; --track-color: var(--un-preset-theme-colors-basebg);` : ''
				}`}
			/>
			{props.children}
		</div>
	)
}
export const DynamicColored: ParentComponent<
	{
		text: string
	} & JSX.HTMLAttributes<HTMLSpanElement>
> = (props) => {
	const [ourProps, otherProps] = splitProps(props, ['text', 'children'])
	const color = createMemo(() => stringToColor(ourProps.text))

	return (
		<span
			{...otherProps}
			style={mergeStyles(otherProps.style, {
				'color': isColorDark(color()) ? 'white' : 'black',
				'background-color': color(),
			})}
		>
			{ourProps.children || ourProps.text}
		</span>
	)
}

export const [/* _idHover */, useIdHover] = makeGlobalHover((active: boolean, myID: boolean) => ({
	'data-test': 123,
	'class': classNames(
		'transition-duration-300 transition-property-[opacity]',
		(active || myID) ? 'opacity-100' : 'opacity-40',
		myID && 'font-bold underline',
	),
}))
// TODO: useChangeHighlight (?)
export const HighlightSameOnHover: ParentComponent<
	{
		id: string
	} & JSX.HTMLAttributes<HTMLSpanElement>
> = (props) => {
	const [ourProps, otherProps] = splitProps(props, ['id', 'children'])
	return (
		<span
			{...(useIdHover('?', ourProps.id))}
			{...otherProps}
		>
			{ourProps.children}
		</span>
	)
}

export const IconifyNames = mapArrayToObj(phosphorIcons)
type PhosphorNames = typeof phosphorIcons[number]
type OtherNames = typeof otherIcons[number]

export type IconName = PhosphorNames | OtherNames | null

// https://icon-sets.iconify.design/ph/
export const Iconify: Component<{
	name: IconName
	size?: number | string
	scale?: number | string
	class?: string
	style?: JSX.CSSProperties
	customSVG?: () => SVGElement // URLencoded svg
	[x: string]: any
}> = (fullProps) => {
	const [props, otherProps] = splitProps(fullProps, ['class', 'size', 'scale', 'name', 'style', 'customSVG'])
	const cursorClass = (typeof otherProps.onclick === 'function') ? 'cursor-pointer' : ''
	const sizes = createMemo(() =>
		props.size
			? (
					(typeof props.size === 'string' && props.size.includes(' '))
						? props.size.split(' ')
						: [props.size, props.size]
				)
			: [4, 4],
	)
	const customSVGdataURLstring = () => {
		if (props.customSVG && props.customSVG()) {
			DEBUG('customSVG', { propsstyle: props.style }, svgElementToDataURL(props.customSVG()))
			return `url(${svgElementToDataURL(props.customSVG())})`
		}
	}
	const iconUUID = `iconify-${uniqueId()}`
	return (
		<div
			id={iconUUID}
			class={classNames(
				// 'iconify-n3',
				props.class,
				cursorClass,
				props.name && ((props.name.includes(':') ? '' : 'i-ph:') + props.name), // can serve as a placeholder for an icon that is there sometimes
				`w-${sizes()[0]} h-${sizes()[1]}`,
			)}
			style={props.scale
				? {
						...(props.style ?? {}),

						'-webkit-mask-size': `${props.scale}%`,
						'-webkit-mask-position': 'center',
					}
				: props.style}
			{...otherProps}
		>
			<Show when={customSVGdataURLstring()}>
				<style>
					{`
					#${iconUUID} {
						--un-icon: ${customSVGdataURLstring()};
					}
					`}
				</style>
			</Show>
		</div>
	)
}

export const ResourceSpinner: ParentComponent<{ resource: Resource<any>, spinner?: JSX.Element }> = (props) => {
	createEffect(() => props.resource.error && ERROR(`ResourceSpinner error:`, props.resource.error)) // otherwise, we just render but don't log
	return (
		<Suspense
			fallback={props.spinner ?? <Spinner />}
		>
			<Show
				when={!props.resource.error}
				fallback={(
					<span color-yellow>
						<div class='i-ph:warning-bold' />
						{props.resource.error.message}
					</span>
				)}
			>
				{props.children}
			</Show>
		</Suspense>
	)
}
export const KidCount: Component<{ block: string }> = (props) => {
	const rawDS = useRawThread()
	const [kidCount] = createDeferredResource(() => props.block, async (block) => {
		// if (Math.random() > 0.5) throw new Error(`TEST err`)
		// for (let index = 0; index < 1000000; index++) {
		// 	Math.random()
		// 	// DEBUG(`T`)
		// }
		return BlockVM.get(block, rawDS).recursiveKidCount
	})
	return (
		<ResourceSpinner resource={kidCount}>
			<span>{kidCount()}</span>
		</ResourceSpinner>
	)
}

export function* getPersistenceStory() {
	// https://storage.spec.whatwg.org/#persistence
	// new situation apparently
	if (navigator.storageBuckets) { // chrome only ?
		const inboxBucket = yield navigator.storageBuckets.open('note3keys', {
			durability: 'strict', // Or `'relaxed'`.
			persisted: true, // Or `false`.
		})
	}
	const wasPersisted = yield navigator.storage.persisted()
	const persistGranted = yield navigator.storage.persist()
	const estimate = yield navigator.storage.estimate()
	WARN(`Persisted storage status:`, { persistGranted, wasPersisted, estimate })
	return { persistGranted, wasPersisted }
}
export async function askForStoragePerms() {
	const isChromium = !!(window as any).chrome // https://stackoverflow.com/a/62797156/
	if (isChromium) {
		VERBOSE.force('try grant notification')
		const notificationGrantHack = await Notification.requestPermission() // https://stackoverflow.com/a/53573849/2919380
		DEBUG.force('notificationGrantHack result', notificationGrantHack) // will be string 'granted' upon request
	}
	const persistStillNotGranted = !(await navigator.storage.persist())
	if (persistStillNotGranted) {
		getPersistenceStory()
		window.location.reload()
	} else {
		DEBUG('Storage permissions acquired :)')
		setStorageError(null)
	}
}
export const StoragePermsErr: Component<{
	bold: boolean
	[x: string]: any // TODO keyof typeof Iconify props somehow
}> = (fullProps) => {
	const isChromium = !!(window as any).chrome // https://stackoverflow.com/a/62797156/
	return (
		<div flex='~ col'>
			<div>
				Persistent storage permission is not granted, your data might not persist.
				<br />
				<Show when={isChromium}>
					In chromium, there is no way to ask for this permission. 🙄
					<br />
					<a target='_blank' href='https://stackoverflow.com/a/53573849/2919380'>Awkwardly enough</a>
					, Notification Permissions are the best way to (maybe) get persistent storage, so:
				</Show>
				<Show when={!isChromium}>
					You need to grant the permission in the site settings in your browser.
				</Show>
			</div>
			<sl-button size='small' mt-3 self-end onClick={askForStoragePerms}>
				Click to {isChromium ? 'request Notification' : 'check for'} permissions
			</sl-button>
		</div>
	)
}

type CloudIcon = 'cloud-check' | 'cloud-slash' | 'cloud-check-bold' | 'cloud-slash-bold' | 'cloud-warning' | 'cloud-warning-bold'
export const Online: Component<{
	bold: boolean
	[x: string]: any // TODO keyof typeof Iconify props somehow
}> = (fullProps) => {
	const [props, otherProps] = splitProps(fullProps, ['bold'])
	const iconName = createMemo(() => {
		const bold = props.bold ? '-bold' : ''
		const warningOrCheck = !isStorageReachable() ? '-warning' : '-check'
		DEBUG({ bold, warning: warningOrCheck })

		return (isOnline()
			? `cloud${warningOrCheck}${bold}`
			: `cloud-slash${bold}`) as CloudIcon
	})

	const tt = createAsyncMemo(async () => {
		if (isOnline()) {
			if (isStorageReachable()) {
				return 'All good'
			} else {
				if (!initialized()) return <span>online, but storage not reachable and app not initialized</span>
				const storageSituation = await getStorageIssues()
				LOG({ storageSituation })
				return (
					<div flex='~ col' gap-1>
						<span>online, but storage not reachable</span>
						<For each={Object.entries(storageSituation)}>
							{([eachURL, eachRes]) => (
								<sl-button variant={eachRes.ok ? 'success' : 'danger'}>
									<Iconify slot='prefix' name={eachRes.ok ? 'check-circle' : 'x-circle'} />
									{eachURL}
								</sl-button>
							)}
						</For>
					</div>
				) // TODO more specific feedback about failures
			}
		} else {
			return 'Offline: Check your device connection'
		}
	})
	return (
		<Show when={initialized() /* && (!isOnline() || !isStorageReachable()) */}>
			<sl-tooltip
				// hoist
				cursor-pointer
				trigger='click hover'
				placement='bottom'
			>
				<Iconify onclick={async () => LOG(await getStorageIssues())} {...otherProps} name={iconName()} />
				<div slot='content'>
					{tt()}
				</div>
			</sl-tooltip>
		</Show>
	)
}

export function createDeferredResource<R, S>(
	source: S | false | null | (() => S | false | null),
	fetcher: (arg: S) => Promise<R>,
	{ deferOnUpdate }: { deferOnUpdate?: boolean } = {},
) {
	let loadedOnce = false // ? this was a preemptive measure, not sure if needed
	return createResource(source, async (source) => {
		// await new Promise<void>(resolve => queueMicrotask(resolve)) // (i) https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide#timeout_and_microtask_example
		DEBUG(`[createDeferredResource] loadedOnce=${loadedOnce}, deferOnUpdate=${deferOnUpdate}`)
		if (!loadedOnce || deferOnUpdate) {
			await new Promise<void>(resolve => setTimeout(resolve)) // i.e. defer
		}
		loadedOnce = true
		// await new Promise<void>(resolve => setTimeout(resolve, 1000)) // for testing

		return fetcher(source)
		// const result = await fetcher(source)
		// DEBUG(`[createDeferredResource] result:`, result)
		// return result
	})
}
// export function createDeferredMemo<R>(func: () => R) {
// 	const [val, setVal] = createSignal<R>(null)
// 	setTimeout(() => {
// 		// await new Promise<void>(resolve => queueMicrotask(resolve)) // (i) https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide#timeout_and_microtask_example
// 		await new Promise<void>(resolve => setTimeout(resolve)) // i.e. defer
// 		// await new Promise<void>(resolve => setTimeout(resolve, 1000)) // for testing
// 		return func()
// 	})
// 	return val
// }

export const DeleteWithConfirm: Component<
	DivProps & {
		handler: () => Promise<void> | void
		label?: string
		confirmText?: string
		confirmButtonLabel?: string
		buttonVariant?: string
		buttonIcon?: string
		certaintySeconds?: number
	}
> = (allProps) => {
	const [props, restProps] = splitProps(allProps, [
		'label',
		'handler',
		'confirmText',
		'certaintySeconds',
		'buttonVariant',
		'buttonIcon',
		'confirmButtonLabel',
	])

	const [opened, setOpened] = createSignal(false)
	const [openedSecs, setOpenedSecs] = createSignal(0)
	createTimer(() => setOpenedSecs(s => s + 1), () => opened() && 1000, setInterval)
	createEffect(() => !opened() && setOpenedSecs(0))

	const deleteButtonProps = createAsyncButtonHandler(props.handler)

	return (
		<sl-dropdown
			// onClick={stopPropagation}
			placement='bottom-start'
			distance={3}
			{...restProps}
			onsl-show={() => setOpened(true)}
			onsl-hide={() => setOpened(false)}
		>
			<sl-button slot='trigger' size='small' variant={props.buttonVariant || 'danger'}>
				<Iconify name={props.buttonIcon || 'trash-duotone'} slot='prefix' />
				{props.label}
			</sl-button>
			<div class='darkdropdown outline-rounded-white p-4 line-height-5' flex='~ col gap-4'>
				<div whitespace-pre-line>{props.confirmText ?? 'You sure bout\' dat?'}</div>
				<sl-button
					class=''
					slot='trigger'
					size='small'
					variant='danger'
					{...deleteButtonProps()}
					disabled={props.certaintySeconds && openedSecs() < props.certaintySeconds}
				>
					<div w-4 h-4 class='i-ph:trash-duotone' />
					{props.certaintySeconds && openedSecs() < props.certaintySeconds
						? `Think ${(props.certaintySeconds - openedSecs())}s`
						: (props.confirmButtonLabel || 'Yes, Delete')}
				</sl-button>
			</div>
		</sl-dropdown>
	)
}

export const DeleteWithConfirmDialog: Component<
	DivProps & {
		handler: () => Promise<void> | void
		label?: string
		dialogText?: string | Element
		dialogLabel?: string
		certaintySeconds?: number
	}
> = (allProps) => {
	const [props, restProps] = splitProps(allProps, ['label', 'handler', 'dialogText', 'certaintySeconds', 'dialogLabel'])

	const [opened, setOpened] = createSignal(false)
	const [openedSecs, setOpenedSecs] = createSignal(0)
	createTimer(() => setOpenedSecs(s => s + 1), () => opened() && 1000, setInterval)
	createEffect(() => !opened() && setOpenedSecs(0))

	const deleteButtonProps = createAsyncButtonHandler(props.handler)

	let dialogRef
	return (
		<>
			<sl-button size='small' variant='danger' onClick={() => dialogRef?.show()}>
				<div w-4 h-4 class='i-ph:trash-duotone' slot='prefix' />
				{props.label}
			</sl-button>
			<sl-dialog
				{...restProps}
				ref={dialogRef}
				label={props.dialogLabel ?? 'Really delete?'}
				onsl-show={() => setOpened(true)}
				onsl-hide={() => setOpened(false)}
			>
				<div flex='~ col gap-4'>
					<div whitespace-pre-line>{props.dialogText ?? 'You sure bout\' dat?'}</div>
					<sl-button
						slot='footer'
						variant='danger'
						{...deleteButtonProps()}
						disabled={props.certaintySeconds && openedSecs() < props.certaintySeconds}
					>
						<div w-4 h-4 class='i-ph:trash-duotone' />
						{props.certaintySeconds && openedSecs() < props.certaintySeconds
							? `Think ${(props.certaintySeconds - openedSecs())}s`
							: 'Yes, Delete'}
					</sl-button>
				</div>
			</sl-dialog>
		</>
	)
}

export const PubInfoBox: Component<{ pubID?: string | null, pinCID?: string, label?: string, carFile?: CarReader }> = (props) => {
	const appThread = useRawThread()

	const [fetchedPub] = createDeferredResource(
		() => ({ pubID: props.pubID, pinCID: props.pinCID, carFile: props.carFile }),
		async ({ pubID, pinCID, carFile }) => /* : Promise<Partial<ReturnType<typeof retrievePubDataWithExtras>>> */ {
			DEBUG(`PubInfoBox.fetch`, { pubID, pinCID })
			if (!pubID && !pinCID && !carFile) return null
			// if (matchingSubOrPub()) return null
			// throw new Error(`TEST pubinfo err`)
			if (carFile) {
				const { applogs, info } = await decodePubFromCar(carFile)
				// TODO: display INFO
				const [encryptedLogs, plainLogs] = partition(applogs, isEncryptedApplog)
				const thread = ThreadInMemory.fromArray((plainLogs as any) as Applog[], `preview-carfile`)
				return {
					info,
					thread,
					encryptedCount: encryptedLogs.length,
					...getPubExtraInfo(appThread, thread),
				}
			} else {
				const thread = ThreadInMemory.empty(`pubInfo-${pinCID || pubID}`)
				const { cid, info } = await retrievePubToThread(thread, pubID, { pinCID }, appThread)
				return {
					info,
					thread,
					cid,
					// encryptedCount,
					...getPubExtraInfo(appThread, thread),
				}
			}
		},
	)

	return (
		<ResourceSpinner resource={fetchedPub}>
			<Show when={fetchedPub()}>
				<div p-2 border='1 solid lightblue-700' rounded gap-2>
					<PubInfos pub={fetchedPub()} label={props.label} />
				</div>
			</Show>
		</ResourceSpinner>
	)
}

export const PubInfos: Component<{
	pub: PromiseType<ReturnType<typeof retrievePubDataWithExtras>>
}> = (props) => {
	const agent = useAgent()
	const info = createMemo(() => props.pub.info)
	// const encryptedApplogCount = info().maybeEncryptedApplogs.filter(log => !log?.ag).length // encrypted logs are byte arrays, so they have no .ag prop // HACKish
	// const encryptedFor= filterAndMap(lastWriteWins(info().thread), { en: publicationNameString, at: 'pub/encryptedFor' }, 'vl') // no need for a filter just doing a find below instead
	const infoLogs = createMemo(() => info().logs)
	const encryptedFor = queryAndMap(infoLogs(), { at: 'pub/sharedKey' }, 'en')
	const pubName = querySingleAndMap(infoLogs(), { at: 'pub/name' }, 'vl') // TODO: editable :)
	const pubBy = querySingleAndMap(infoLogs(), { at: 'pub/name' }, 'en') // TODO: editable :)
	const sharedKeyLog: Applog = agent.getSharedKeyApplogForCurrentAgent(infoLogs())
	DEBUG({ sharedKeyLog, encryptedFor })
	const isEncryptedForMe = createMemo(() => encryptedFor.includes(agent.ag))
	const encryptedForWithoutMe = createMemo(() =>
		encryptedFor.filter(eachEn => eachEn !== agent.ag)
			.map(eachOtherEn => [eachOtherEn, `${agent.getKnownAgents().get()?.get(eachOtherEn)?.agString || 'unknown'}`]),
	)
	// if (sharedKeyLog) encryptedFor = sharedKeyLog.en
	// TODO check agents for if we know their agent string. have any atoms from them, and have a public derivation key from them
	return (
		<Show when={info()}>
			<Show when={pubName.get()}>
				<KeyValueDiv label='Name' class='text-sm'>
					{pubName.get()}
				</KeyValueDiv>
			</Show>
			<Show when={encryptedFor.size}>
				<KeyValueDiv label='Encrypted' class='text-xs'>
					{encryptedFor.toString()}
				</KeyValueDiv>
			</Show>
			<KeyValueDiv label='Agents' class='text-xs'>
				<span class='grow-1 overflow-hidden text-ellipsis whitespace-nowrap'>{props.pub.agents.join(', ') /* TODO sharedKeyLogs  */}</span>
			</KeyValueDiv>
			<KeyValueDiv label='Timerange' class='text-xs'>
				<Show when={props.pub.thread.size} fallback='Empty Thread'>
					<sl-relative-time date={props.pub.thread.firstLog?.ts} />
					➜
					<sl-relative-time date={props.pub.thread.latestLog?.ts} />
				</Show>
			</KeyValueDiv>
			<KeyValueDiv label='CID' class='text-xs'>
				<a
					href={explorerUrl(props.pub.cid.toString())}
					target='_blank'
					overflow-hidden
					text-ellipsis
					class='color-inherit visited:color-inherit'
				>
					<code>{props.pub.cid.toString()}</code>
				</a>
			</KeyValueDiv>
			<KeyValueDiv label='Content' class='text-xs'>
				{`${props.pub.thread.size} Applogs `}
				<span class={props.pub.newLogs ? 'color-blue' : 'color-green'}>
					({props.pub.newLogs ? `of which ${props.pub.newLogs} are not in the local data` : `all exist in your local data`})
				</span>
				<br />
				<Show when={props.pub.encryptedCount}>
					<div>
						encrypted logs for: {isEncryptedForMe()
							? (
									<sl-tooltip placement='right' style={{ '--max-width': '300px' }}>
										{` you & ${encryptedForWithoutMe().length} others`}
										<div slot='content' min-w-max w-max>
											<div flex='~ col' class='items-start'>
												<For each={encryptedForWithoutMe()}>
													{(agentInfo, _index) => <div text-left>{agentInfo[0]}:{agentInfo[1]}</div>}
												</For>
											</div>
										</div>
									</sl-tooltip>
								)
							: ' NOT you: '}
					</div>
				</Show>
			</KeyValueDiv>
			<KeyValueDiv
				label='Content'
				class={classNames(
					'text-xs',
					props.pub.entityOverlapCount.get() && props.pub.newLogs ? 'color-yellow' : '',
				)}
			>
				Related to
				{' '}
				<strong>{props.pub.entityOverlapCount.get()} entities</strong>
				{' '}
				in your local data
			</KeyValueDiv>
		</Show>
	)
}

export const NameValueBadge: ParentComponent<{ name: string, variant?: string }> = (props) => {
	return (
		<sl-badge variant={props.variant ?? 'neutral'}>
			<span>
				<strong>{props.name}:</strong>
				{' '}
				{props.children}
			</span>
		</sl-badge>
	)
}
export const KeyValueDiv: ParentComponent<DivProps & { label: string }> = (allProps) => {
	const [props, restProps] = splitProps(allProps, ['label', 'children'])
	return (
		<div flex='~ items-center gap-2' {...restProps}>
			<strong flex='shrink-0 grow-0'>
				{props.label}:
			</strong>
			{props.children}
		</div>
	)
}

export const ButtonGroup: Component<
	DivProps & {
		size?: typeof DefaultSmall
		buttonData: any
	}
> = (allProps) => {
	const [props, topProps] = splitProps(allProps, ['size', 'buttonData'])
	// const { size = DefaultSmall } = props // ! only include non reactive props
	return (
		<sl-button-group size={size} {...topProps}>
			<For each={props.buttonData}>
				{({ restProps, icon, click }) => (
					<sl-button
						{...restProps}
						onClick={click}
						size={props.size ?? DefaultSmall}
					>
						<Iconify name={icon} />
					</sl-button>
				)}
			</For>
		</sl-button-group>
	)
}
export const AgentButton: Component<
	DivProps & {
		size?: typeof DefaultSmall
		buttonData: any
	}
> = (allProps) => {
	const [props, topProps] = splitProps(allProps, ['size', 'buttonData'])
	// const { size = DefaultSmall } = props // ! only include non reactive props
	const { restProps, icon, click, text, title } = props.buttonData
	return (
		<sl-button
			{...restProps}
			onClick={click}
			alt={title}
			title={title}
			aria-label={title}
			size={props.size ?? DefaultSmall}
		>
			<Show when={!!icon}>
				<Iconify name={icon} />
			</Show>
			{text}
		</sl-button>
	)
}

export const FlexBetween: ParentComponent<
	JSX.HTMLAttributes<HTMLDivElement> & {
		w?: typeof DefaultFull
		items?: typeof DefaultCenter
	}
> = (allProps) => {
	// const { children, items = DefaultCenter, w = DefaultFull, class: classes, ...restProps } = props
	const [props, restProps] = splitProps(allProps, ['w', 'children', 'items', 'class'])
	return (
		<div
			flex='~ justify-between'
			class={`${props.class} items-${props.items ?? DefaultCenter} w-${props.w ?? DefaultFull}`}
			{...restProps}
		>
			{props.children}
		</div>
	)
}

export const FileSelect: ParentComponent<{ onFile: (file: FileList) => any }> = (props) => {
	let fileInput: HTMLInputElement

	function onFileChange(this: HTMLInputElement, event) {
		event.preventDefault()
		DEBUG(`[FileSelect] onFileChange`, { self: this, event })
		props.onFile(this.files)
	}
	onMount(() => {
		fileInput.addEventListener('change', onFileChange, false)
		return () => fileInput?.removeEventListener('change', onFileChange, false)
	})
	return (
		<div>
			{/* <strong>{props.children}:</strong>&nbsp; */}
			<input type='file' ref={fileInput} hidden />
			<sl-button size='small' onClick={() => fileInput.click()}>
				{props.children}
			</sl-button>
		</div>
	)
}
export const RedirectWorkaround: ParentComponent<
	DivProps & {
		url: string
		replace?: boolean
	}
> = (props) => {
	const [ourProps, otherProps] = splitProps(props, ['url'])
	const { locnav, location, navigate } = useLocationNavigate()

	// createEffect(()=> { if (isPreviewOrSearch()) {
	queueMicrotask(() => navigate(props.url, { replace: props.replace ?? true }))
	// 	}})

	return (
		<div
			{...otherProps}
		>
			Redirecting to
			{' '}
			<a href={ourProps.url}>
				<code>{ourProps.url}</code>
			</a>
			{props.children}
		</div>
	)
}
