import type { CidString, EntityID, IpnsString, IShare, ISubscription, PromiseType, Thread } from '@wovin/core'
import type { Accessor, Component, JSXElement } from 'solid-js'
import type { retrievePubDataWithExtras } from '../ipfs/store-sync'
import type { DivProps } from './utils-ui'
import { A } from '@solidjs/router'
import { areCidsEqual, integratePub, isShare, lastWriteWins, querySingleAndMap, tryParseCID } from '@wovin/core'
import { Logger } from 'besonders-logger'
import classNames from 'classnames'
import { createMemo, Show, splitProps, Suspense } from 'solid-js'
import { Iconify, PubInfos, ShortID, Spinner } from '../components/mini-components'
import { useAgent } from '../data/agent/AgentState'
import { onlyFromCurrentAgent } from '../data/lazy-agent'
import { upsertSubscription } from '../ipfs/share-sync'
import { updateSubFromPullData } from '../ipfs/store-sync'
import { doSync, syncState } from '../ipfs/sync-service'
import { createAsyncButtonHandler, explorerUrl, notifyToast, useLocationNavigate } from './utils-ui'

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

export const PreviewInfoPanel: Component<{
	targetThread: Thread
	matchingSubOrShare: IShare | ISubscription | null
	previewData: Accessor<PromiseType<ReturnType<typeof retrievePubDataWithExtras>>>
	subID?: string
	refetch: () => void
	label?: string

	// slots
	ExtraButtons?: JSXElement
}> = (props) => {
	const agent = useAgent()
	// const location = useLocation()
	// const navigate = useNavigate()
	// DEBUG('<PreviewInfoPanel>', { subID: props.subID })

	const subID = createMemo(() => props.matchingSubOrShare?.id ?? props.subID ?? props.previewData()?.id)
	const matchingIsShare = createMemo(() => !!props.matchingSubOrShare && isShare(props.matchingSubOrShare))
	const matchingSubShareLastCid = createMemo(() => {
		if (!matchingIsShare()) {
			return subscriptionPulls(props.targetThread, subID())
		} else {
			const matchingShare = agent.sharesMap.get(subID())
			DEBUG({ matchingShare })
			return matchingShare?.lastCID
		}
	})

	const previewIsFullyIntegrated = () => {
		DEBUG('previewIsFullyIntegrated', { previewData: props.previewData(), matchingSubShareLastCid: matchingSubShareLastCid() })
		return props.previewData() && matchingSubShareLastCid() && areCidsEqual(props.previewData().cid, matchingSubShareLastCid())
	}

	const pullSub = async () => {
		await doSync({ sub: subID() })
		props.refetch()
	}

	return (
		<sl-alert variant='primary' open>
			<div flex='~ items-center gap-2'>
				<div flex='shrink-0' class='i-ph:eye-bold' />
				<strong flex-shrink-0>
					{props.label ?? 'Previewing thread'}:
				</strong>
				<span overflow-hidden text-ellipsis>
					<code>{subID()}</code>
				</span>
			</div>

			<Suspense fallback={<Spinner />}>
				<Show when={props.previewData()}>
					<div mt-1 px-2 py-1 border='1 solid lightblue-700' rounded gap-2>
						<PubInfos pub={props.previewData()} />
					</div>
				</Show>
			</Suspense>

			<div flex='~ justify-between wrap' gap-4 mt-2>
				<div>
					<Show when={props.matchingSubOrShare}>
						This is
						{' '}
						<A
							href={`/settings/${matchingIsShare() ? 'shares' : 'subscriptions'}/${props.matchingSubOrShare.id}`}
							class='color-blue visited:color-blue'
						>
							{matchingIsShare() ? 'your share' : 'a subscription in your list'}
						</A>
						{' '}
						<Suspense fallback={<Spinner />}>
							{/* <Show when={true || !previewIsFullyIntegrated()}> */}
							<span
								class={classNames([
									!matchingIsShare() && 'dark:color-yellow color-yellow-600',
								])}
							>
								(last
								{' '}
								{matchingIsShare() ? 'pushed' : 'integrated'}
								{' '}
								CID:
								{' '}
								<Show when={matchingSubShareLastCid()} fallback='none yet'>
									<ShortID id={matchingSubShareLastCid().toString()} href={explorerUrl(matchingSubShareLastCid())} />
								</Show>
								)
							</span>
						</Suspense>
					</Show>
				</div>
				<div flex='grow-1 ~ items-center justify-end' gap-2>
					{props.ExtraButtons}
					<Suspense fallback={<Spinner />}>
						<Show when={!props.matchingSubOrShare || !previewIsFullyIntegrated()}>
							<Show when={!props.matchingSubOrShare}>
								<SubIntegrateDropdown
									isFullyIntegrated={previewIsFullyIntegrated()}
									targetThread={props.targetThread}
									subID={subID()}
									previewData={props.previewData()}
								/>
							</Show>
							<Show when={!previewIsFullyIntegrated() && props.matchingSubOrShare && !matchingIsShare()}>
								<sl-button
									size='small'
									variant='primary'
									slot='trigger'
									loading={Array.isArray(syncState.syncing) && syncState.syncing.some(entry => entry.sub?.id === props.matchingSubOrShare.id)}
									onClick={pullSub}
								>
									<Iconify slot='prefix' name='download-simple-bold' />
									Pull subscription
								</sl-button>
							</Show>
						</Show>
					</Suspense>
				</div>
			</div>
		</sl-alert>
	)
}
function subscriptionPulls(targetThread: Thread, subID: EntityID): string {
	return querySingleAndMap(
		lastWriteWins(onlyFromCurrentAgent(targetThread)),
		{ en: subID, at: 'subscription/cid' },
		'vl',
	).get() as string | undefined
}

export const SubIntegrateDropdown: Component<
	DivProps & {
		subID: CidString
		previewData: PromiseType<ReturnType<typeof retrievePubDataWithExtras>>
		targetThread: Thread
		isFullyIntegrated: boolean
	}
> = (allProps) => {
	const [props, restProps] = splitProps(allProps, ['subID', 'targetThread', 'previewData', 'isFullyIntegrated'])

	const agent = useAgent()
	const { locnav, location, navigate } = useLocationNavigate()
	const parsedCID = createMemo(() => tryParseCID(props.subID))

	function integrate() {
		return integratePub({ targetThread: props.targetThread, agentHash: agent.ag, subID: props.previewData.id, pubData: props.previewData })
	}
	const integrateOnceHandlerProps = createAsyncButtonHandler(() => {
		const integratedLogs = integrate()
		// props.refetch() // ? why
		notifyToast(`Successfully integrated ${integratedLogs.length} applogs`, 'success')
	})
	const integrateAndSubHandlerProps = createAsyncButtonHandler(async function integrateOnce() {
		// if (matchingIsShare()) throw ERROR("shouldn't integrate own share", props)
		if (parsedCID().errors) throw ERROR('subID has errors', { subID: props.subID, parsed: parsedCID() })
		if (!parsedCID().isIpns) throw ERROR('subID is not IPNS', { subID: props.subID, parsed: parsedCID() })
		const integratedLogs = integrate()
		const shareName
			= (querySingleAndMap(props.previewData.info.logs, { at: 'share/name' }, 'vl').get()
				|| querySingleAndMap(props.previewData.info.logs, { at: 'pub/name' }, 'vl').get()) as string

		const sub = await upsertSubscription(props.subID as IpnsString, { name: shareName })
		updateSubFromPullData(props.previewData, sub.id)
		notifyToast(`Successfully integrated ${integratedLogs.length} applogs & added subscription`, 'success')
		navigate(`/settings/subscriptions/${sub.id}`)
	})

	return (
		<>
			<Show when={!props.isFullyIntegrated}>
				<sl-dropdown placement='bottom-end' {...restProps}>
					<sl-button
						size='small'
						variant='primary'
						slot='trigger'
						caret
						loading={integrateOnceHandlerProps().loading || integrateAndSubHandlerProps().loading}
					>
						<Iconify slot='prefix' name='download-simple-bold' />
						Integrate
					</sl-button>
					<sl-menu>
						<sl-menu-item {...integrateOnceHandlerProps()}>Integrate Once</sl-menu-item>
						<sl-menu-item {...integrateAndSubHandlerProps()} disabled={!parsedCID().isIpns}>
							Integrate & Subscribe
						</sl-menu-item>
					</sl-menu>
				</sl-dropdown>
			</Show>
			<Show when={props.isFullyIntegrated}>
				<sl-button
					size='small'
					variant='primary'
					slot='trigger'
					loading={integrateAndSubHandlerProps().loading || integrateAndSubHandlerProps().loading}
					onClick={integrateAndSubHandlerProps().onclick}
				>
					<Iconify slot='prefix' name='plus-bold' />
					Add subscription
				</sl-button>
			</Show>
		</>
	)
}
