import type { SlInput } from '@shoelace-style/shoelace'
import type { EntityID } from '@wovin/core'
import type { Accessor, Component } from 'solid-js'
import type { Provider } from '../../data/VMs/ProviderVM'
import { urlFromHumanInput } from '@wovin/utils/browser'
import { Logger } from 'besonders-logger'
import classNames from 'classnames'
import { Collapse } from 'solid-collapse'
import { createMemo, createSignal, For, Show } from 'solid-js'
import { useAgent } from '../../data/agent/AgentState'
import { DefaultAgentBanner } from '../../data/agent/utils-agent'
import { chooseFilesystemFolder, isFileSystemAPIavailable } from '../../data/filesystem-utils'
import { useLocalStorage } from '../../data/utils-data'
import { getVM, getVMs } from '../../data/VMs/MappedVMbase'
import { ProviderVM } from '../../data/VMs/ProviderVM'
import { DEMO_PROVIDER } from '../../ipfs/storage'
import { useCurrentThread, useProviderIDs } from '../../ui/reactive'
import { FlexBetween, Iconify } from '../mini-components'

const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.DEBUG) // eslint-disable-line unused-imports/no-unused-vars

export const StorageSettings: Component<{}> = () => {
	DEBUG('Creating <StorageSettings>') // HACK used to render twice and sideEffects should only happen once if possible
	const thread = useCurrentThread()
	const [apiKey, setApiKey] = createSignal('')
	const [submitted, setSubmitted] = createSignal(false)
	const storageProviderIDs = useProviderIDs()
	const storageProviders = getVMs(ProviderVM, storageProviderIDs)
	// const hasPersistProvider = createMemo(() => hasProviderWithCap(storageProviders, 'persist'))
	const hasDemoProvider = createMemo(() =>
		storageProviders.some(({ type, url }) => type === 'ucan-store-proxy' && url?.includes(DEMO_PROVIDER)),
	)
	const agent = useAgent()
	const [infoMinimized, setInfoMinimized] = useLocalStorage('note3.settings.storage.info-minimized', false)

	return (
		<div flex='~ col' gap-4>
			<DefaultAgentBanner />
			{/* <Show when={agent.isAgentStringSetup}> */}
			{/* <span pt='4' border='b-1 b-solid gray-400' mb='4' /> */}
			<sl-card
				class={classNames(['card-header', infoMinimized() && 'card-nobody'])}
				style={{ '--border-colly': '#ffffff77', '--padding': 'var(--sl-spacing-medium)' }}
			>
				<div
					slot='header'
					flex='~ items-center justify-between'
					class='w-full cursor-pointer gap-2'
					onClick={() => setInfoMinimized(!infoMinimized())}
				>
					Info
					<div
						class={'i-ph:caret-down-bold h-5 w-5 ' + `${infoMinimized() ? 'rotate-0' : 'rotate-180'}`}
						duration-300
						transition-property='[transform]'
					/>
				</div>
				{
					/* <sl-tab-group placement='start'>
					<sl-tab slot='nav' panel='upload-section'>Upload</sl-tab>
					<sl-tab slot='nav' panel='download-section'>Download</sl-tab> */
				}

				<Collapse value={!infoMinimized()}>
					<p mt-0>
						Storage Providers can offer different capabilities:
					</p>
					<ul>
						<li>Access & Retrieval (IPFS)</li>
						<li>Storing data (IFPS)</li>
						<li>Storing state pointers (IPNS)</li>
					</ul>
					<a href='https://wovin.in/storage.html'>Find out about the different options here</a>
					{' '}
					(from self-hosting to paid services)
				</Collapse>
			</sl-card>
			<sl-card class='card-header' style={{ '--border-colly': '#ffffff77', '--padding': 'var(--sl-spacing-medium)' }}>
				<div slot='header'>
					Your storage provider(s)
				</div>
				<div>
					<ProviderList
						ids={storageProviderIDs}
						// createBuilder={() => new ObjectBuilder({ 'wovin/provider/type': 'ucan-store-proxy' })}
					/>
					<Show when={!hasDemoProvider()}>
						<p text-green-500 dark:text-green-300>
							If you just want to try,
							{' '}
							<span
								underline
								cursor-pointer
								onClick={(e) => {
									e.preventDefault()
									const demoGW = storageProviders.find(({ type, url }) => type === 'ipfs-gateway' && url === DEMO_PROVIDER)
									if (demoGW) {
										demoGW.type = 'ucan-store-proxy'
									} else {
										ProviderVM.buildNew({ type: 'ucan-store-proxy', name: 'Note3 Demo Storage', url: DEMO_PROVIDER }).commit(thread)
									}
								}}
							>
								use our demo instance
							</span>
							{'  '}
							(might be offline or reset at any point)
						</p>
					</Show>
				</div>

				{
					/* <div mt-8 opacity-40>
					<h3 mb-0>
						NFT.storage (deprecated & currently not usable)
					</h3>
					<Switch>
						<Match when={!storageState.nftStorage && !submitted()}>
							<form flex='~ col' gap-4 onSubmit={loginNFT}>
								<p my-1>
									Sign up for <a href='https://nft.storage' target='_blank'>nft.storage</a> & create an API key
								</p>
								<sl-input
									type='text'
									placeholder='API Key'
									required
									filled
									value={apiKey()}
									onInput={e => setApiKey(e.target.value)}
									max-w-md
								/>
								<div slot='footer' flex='~ justify-end md:justify-start' gap-2>
									<sl-button
										size='small'
										type='submit'
										disabled={!apiKey() || submitted()}
										variant='primary'
									>
										Log in
									</sl-button>
								</div>
							</form>
						</Match>
						<Match when={!!storageState.nftStorage}>
							{/* TODO setup a collapse tree here * /}
							<div mt-2 mb-6>
								NFT.Storage UCAN:
								<pre>{storageState.nftStorage.rootUcan ? JSON.stringify(storageState.nftStorage.rootUcan?.payload, undefined, 4) : 'Got API key, but not lazy-loaded yet'}</pre>
							</div>
							<div slot='footer' flex='~ justify-end' gap-2>
								<a href='https://nft.storage/files/' target='_blank'>
									<sl-button size='small'>
										{/* <sl-icon slot='suffix' name='box-arrow-up-right'></sl-icon> * /}
										<div slot='suffix' class='i-ph:arrow-square-out'></div>
										nft.storage account
									</sl-button>
								</a>
								<sl-button
									size='small'
									variant='danger'
									onclick={logoutNFT}
								>
									Log out
								</sl-button>
							</div>
						</Match>
					</Switch>
				</div> */
				}
				<div mt-6 opacity-20>
					<h3 mb-0>
						web3.storage
					</h3>
					<p>
						(currently not usable because of
						{' '}
						<a href='https://blog.web3.storage/posts/the-data-layer-is-here-with-the-new-web3-storage' target='_blank'>infra changes</a>
						{' '}
						we need to adapt to)
					</p>
				</div>
				{/* </sl-tab-group> */}
			</sl-card>
			{
				/*				<sl-card style='--border-colly: #ffffff77; --padding: var(--sl-spacing-medium)'>
					<div slot='header'>
						Your Download Gateways
						{/* <sl-icon-button name="gear" label="Settings"></sl-icon-button> * /}
					</div>
					<div name='download-section'>
						<OrderedStrings stringArray={gateways} onAdd={addRetrievalGateway} />
					</div>
				</sl-card>
					*/
			}
			{/* </Show> */}
			{/* <Show when={isFileSystemAPIavailable()}> */}
			<sl-card class='card-header' style={{ '--border-colly': '#ffffff77', '--padding': 'var(--sl-spacing-medium)' }}>
				<div slot='header'>
					Local Filesystem
				</div>
				<div>
					<p mt-0>
						All publications will additionally be stored in a chosen folder on your local filesystem. (fine-grained control
						{' '}
						<a href='https://gitlab.com/wovin/wovin/-/issues/51#note_1750149332' target='_blank'>planned</a>
						)
					</p>
					<Show when={isFileSystemAPIavailable()}>
						{/* <Show when={!await agent.getDirectoryHandle()}> */}
						<sl-button class='mr-6' onClick={chooseFilesystemFolder}>
							<Iconify slot='prefix' name='floppy-disk' />
							Choose Folder
						</sl-button>
						{/* </Show> */}
						<Show when={agent.getDirectoryHandle() /* TODO handle async */}>
							<p>
								<strong>Selected folder:</strong>
								{' '}
								<code>TODO</code>
							</p>
							<p mb-0>
								Note: in chromium &lt; v122,
								{' '}
								<a
									href='https://developer.chrome.com/blog/persistent-permissions-for-the-file-system-access-api#the_new_way_whats_changing_and_when'
									target='_blank'
								>
									you need to set some flags
								</a>
								, otherwise permission will need to be asked for after closing all tabs.
							</p>
						</Show>
					</Show>
					<Show when={!isFileSystemAPIavailable()}>
						<p>
							FileSystem access is only available on chromium based browsers for now.
							<br />
							<br />
							<a href='https://gitlab.com/wovin/wovin/-/issues/51#note_1748360468'>Check out the wovin issue about the situation.</a>
						</p>
					</Show>
				</div>
			</sl-card>

			{/* </Show> */}
			{
				/* <sl-card class='card-header' style='--border-colly: #ffffff77; --padding: var(--sl-spacing-medium)'>
				<div slot='header'>
					Test AppLog
				</div>
				<div></div>
			</sl-card> */
			}
		</div>
	)
}

export const ProviderList: Component<{
	ids: readonly EntityID[]
	// createBuilder: () => ObjectBuilder<any, any>
}> = (props) => {
	const thread = useCurrentThread()
	// const debouncedThread = debounceWrites(thread)
	let newUrlRef: SlInput
	let newTypeRef: SlInput

	const create = () => {
		const builder = ProviderVM.buildNew({ type: (newTypeRef.value as Provider['type']), url: urlFromHumanInput(newUrlRef.value) })
		LOG(`Creating provider:`, builder)
		builder.commit(thread)
		newUrlRef.value = ''
	}
	const markDeleted = (en: EntityID) => {
		LOG(`Deleting provider:`, en)
		ProviderVM.get(en, thread).setDeleted()
	}

	return (
		<div w-full flex='~ col' gap='2 sm:4'>
			<For each={props.ids}>
				{(providerID) => {
					// const [provider, updateProvider] = withDS(debouncedThread, () => useEntityAttrs(en, ['url', 'type'] as const))
					// createEffect(() => LOG(`provider logs`, query(debouncedThread, { en }).leafNodeLogs))
					const provider = getVM(ProviderVM, providerID)
					LOG(`Provider`, providerID, provider)

					const onURLchange = (evt) => {
						LOG('onURLchange', { evt, val: evt.target.value })
						provider.buildUpdate({ url: urlFromHumanInput(evt.target.value) }).commit(thread)
					}
					return (
						<sl-card w-full style={{ '--border-colly': '#ffffff44', '--padding': 'var(--sl-spacing-small)' }}>
							<div slot='header' w-full flex='~ items-center justify-between'>
								<div>
									<strong>{provider.type as string}</strong>
									{'  '}
									<span>{provider.name as string}</span>
								</div>
								<sl-button variant='danger' size='small' onClick={e => e.button === 0 && markDeleted(provider.en)}>
									<Iconify name='trash-bold' scale={120} />
								</sl-button>
							</div>
							<div flex='~ wrap items-center gap-1'>
								<sl-input
									flex='grow'
									value={provider.url}
									placeholder='Domain / URL'
									onsl-change={onURLchange}
								/>
							</div>
						</sl-card>
					)
				}}
			</For>
			<form
				mt-2
				flex='~ items-center gap-1'
				onSubmit={(evt) => {
					evt.preventDefault()
					create()
				}}
			>
				<sl-select ref={newTypeRef} size='small' placeholder='Select type' required>
					<sl-option value={'ucan-store-proxy' as Provider['type']}>UCAN Store Proxy</sl-option>
					<sl-option value={'ipfs-gateway' as Provider['type']}>IPFS Gateway</sl-option>
				</sl-select>
				<sl-input
					required
					ref={newUrlRef}
					size='small'
					class='w-full'
					placeholder='Add new provider URL'
				/>
				<sl-button variant='primary' size='small' type='submit'>
					<Iconify name='plus-bold' slot='prefix' />
					Add
				</sl-button>
			</form>
		</div>
	)
}

export const OrderedStrings: Component<{ stringArray: Accessor<string[]>, onAdd?: (string) => void }> = (props) => {
	return (
		<div>
			<For each={props.stringArray()}>
				{(eachString: string, _nodeIdx) => {
					return <sl-input class='mb-2' value={eachString} />
				}}
			</For>
			<Show when={props.onAdd}>
				<FlexBetween>
					<sl-button variant='primary' size='medium' circle>
						<Iconify scale='138' class='' name='plus-bold' />
					</sl-button>
					<sl-input class='my-1 ml-2 w-full' onsl-blur={evt => props.onAdd(evt.target.value)} />
				</FlexBetween>
			</Show>
		</div>
	)
}
