import type { EntityID } from '@wovin/core/applog'
import type { Component } from 'solid-js'
import type { phosphorIcons } from '../../unocss.safelist'
import type { QuickSharePhase } from '../ipfs/quick-share'
import type { DivProps } from '../ui/utils-ui'
import { useLocation, useNavigate } from '@solidjs/router'
import { Logger } from 'besonders-logger'
import classNames from 'classnames'
import { createMemo, createSignal, For, onMount, Show, splitProps } from 'solid-js'
import { useAgent } from '../data/agent/AgentState'
import { insertApplogs } from '../data/ApplogDB'
import { useBlockContext } from '../data/block-ui-helpers'
import { copyToClipboard } from '../data/block-ui-helpers-paste'
import {
	addBlock,
	getAddBlockRelationLogs,
	getRecursiveKidsJSON,
	getRecursiveKidsOPML,
	indentBlk,
	outdentBlk,
	removeBlockRelAndMaybeDelete,
} from '../data/block-utils'
import { useBlk } from '../data/VMs/BlockVM'
import { REL, useRel } from '../data/VMs/RelationVM'
import { quickShareBlock } from '../ipfs/quick-share'
import { useAppSettings } from '../ui/app-settings'
import { useCurrentThread, useRawThread, useReadOnlyState, useRelation } from '../ui/reactive'
import { focusViewOnBlock, isTouchDevice, makeNote3Url, notifyToast, onClickOrLongPress, useLocationNavigate } from '../ui/utils-ui'
import { FlexBetween, Iconify, Spinner } from './mini-components'

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

const [openSignal, setShareChooserOpen] = createSignal(false)
const [shareChooserBlockID, setShareChooserBlockID] = createSignal<EntityID | null>(null)
const [onShareSelection, setOnShareSelect] = createSignal(choice => DEBUG('share choice', choice))

export const ShareChooser: Component = () => {
	const onShow = evt => DEBUG('show share chooser', evt)
	const { shares } = useAgent()
	const rawThread = useRawThread()
	const onSel = createMemo(() => evt => onShareSelection()(evt))

	// Quick Share state
	const [quickSharePhase, setQuickSharePhase] = createSignal<QuickSharePhase>('idle')
	const [quickShareUrl, setQuickShareUrl] = createSignal<string | null>(null)
	const [quickShareError, setQuickShareError] = createSignal<string | null>(null)
	const [withoutHistory, setWithoutHistory] = createSignal(true)

	const blockID = createMemo(() => shareChooserBlockID())
	const block = createMemo(() => {
		const id = blockID()
		return id ? useBlk(id) : null
	})

	const resetQuickShare = () => {
		setQuickSharePhase('idle')
		setQuickShareUrl(null)
		setQuickShareError(null)
	}

	const handleQuickShare = async () => {
		const id = blockID()
		if (!id) return
		resetQuickShare()

		try {
			const result = await quickShareBlock(rawThread, id, {
				withoutHistory: withoutHistory(),
				onPhaseChange: setQuickSharePhase,
			})
			setQuickShareUrl(result.url)
			copyToClipboard(result.url)
		} catch (err) {
			ERROR('[ShareChooser] Quick share failed:', err)
			setQuickSharePhase('error')
			setQuickShareError((err as Error).message || 'Unknown error')
		}
	}

	const handleClose = () => {
		// Show toast if we have a successful quick share URL
		const blk = block()
		const id = blockID()
		if (quickSharePhase() === 'done' && quickShareUrl() && blk) {
			const preview = blk.contentPlaintext?.slice(0, 30) || id
			notifyToast(`Quick share link for '${preview}${blk.contentPlaintext?.length > 30 ? '...' : ''}' copied`, 'success')
		}
		setShareChooserOpen(false)
		// Reset state after close
		setTimeout(resetQuickShare, 300)
	}

	return (
		<sl-dialog
			onsl-show={onShow}
			onsl-request-close={handleClose}
			label='Share Block'
			open={openSignal()}
		>
			<sl-tab-group>
				<sl-tab slot='nav' panel='via-publication'>Via Publication</sl-tab>
				<sl-tab slot='nav' panel='quick-share'>Quick Share</sl-tab>

				<sl-tab-panel name='via-publication'>
					<Show
						when={shares.length}
						fallback={<div class='py-4 text-gray-500'>No publications configured. Create one in Settings.</div>}
					>
						<sl-menu
							class='bullet-menu menu-tight'
							onsl-select={onSel()}
						>
							<For each={shares}>
								{({ id, name }) => (
									<sl-menu-item class='-tight -nosub' value={id}>
										<span>{name} - {id.slice(-7)}</span>
									</sl-menu-item>
								)}
							</For>
						</sl-menu>
					</Show>
				</sl-tab-panel>

				<sl-tab-panel name='quick-share'>
					<div class='flex flex-col gap-4 py-2'>
						<p class='m-0 text-sm text-gray-600'>
							Create a shareable link for this block and its children.
						</p>

						<sl-checkbox
							checked={withoutHistory()}
							onsl-change={e => setWithoutHistory(e.target.checked)}
						>
							Without history
						</sl-checkbox>

						<Show when={quickSharePhase() === 'idle'}>
							<sl-button variant='primary' onClick={handleQuickShare}>
								<Iconify slot='prefix' name='share-network-bold' size={4} />
								Share Now
							</sl-button>
						</Show>

						<Show when={quickSharePhase() === 'preparing'}>
							<div class='flex items-center gap-2 text-gray-600'>
								<Spinner size='1.2rem' />
								<span>Preparing snapshot...</span>
							</div>
						</Show>

						<Show when={quickSharePhase() === 'uploading'}>
							<div class='flex items-center gap-2 text-gray-600'>
								<Spinner size='1.2rem' />
								<span>Uploading to storage...</span>
							</div>
						</Show>

						<Show when={quickSharePhase() === 'done' && quickShareUrl()}>
							<div class='flex flex-col gap-2'>
								<div class='flex items-center gap-2 text-green-600'>
									<Iconify name='check-circle-bold' size={5} />
									<span>Uploaded successfully!</span>
								</div>
								<div class='flex items-center gap-2'>
									<sl-input
										class='flex-1'
										value={quickShareUrl()}
										readonly
										size='small'
									/>
									<sl-copy-button value={quickShareUrl()} />
								</div>
							</div>
						</Show>

						<Show when={quickSharePhase() === 'error'}>
							<sl-alert variant='danger' open>
								<Iconify slot='icon' name='warning-bold' size={5} />
								{quickShareError()}
							</sl-alert>
							<sl-button variant='default' onClick={handleQuickShare}>
								Try Again
							</sl-button>
						</Show>
					</div>
				</sl-tab-panel>
			</sl-tab-group>
		</sl-dialog>
	)
}
export const BulletMenu: Component<
	DivProps & {
		blockID: EntityID
		onlyShowOnHover?: boolean
		iconProps: { scale: number, name: typeof phosphorIcons[number], icon: any }
		showBlockSettings: () => void
	}
> = (allprops) => {
	const [props, restProps] = splitProps(allprops, ['blockID', 'iconProps', 'showBlockSettings'])
	const { blockID, showBlockSettings } = props // ! non-reactive
	if (!blockID) return null
	const readOnly = useReadOnlyState()
	const agent = useAgent()
	const { locnav, location, navigate } = useLocationNavigate()
	// const { onCopyLink, onCopyContent, onCopyID, onHistory, onFocus, onDelete, onIndent, onOutent, onReply } = handlers

	// const navigate = useNavigate()
	const block = useBlk(blockID)
	const hasKids = createMemo(() => block.kidRelations.length)

	const appSettings = useAppSettings()

	let triggerRef
	let bulletIconRef
	let menuRef
	const pubChooserRefHolder = { ref: null }
	const handlers = selectionHandlersForBulletMenu(setShareChooserOpen, setOnShareSelect, showBlockSettings)
	const onSelection = (evt) => {
		const itemValue = evt.detail.item.value
		const itemHandlerParams = evt.detail.item.attributes?.['data-handler-param']?.nodeValue
		if (handlers[itemValue]) {
			handlers[itemValue](evt, itemHandlerParams)
		} else {
			WARN('unknown bullet menu item value')
		}
	}
	let preventClickHack = false // HACK - https://chatgpt.com/share/67349aed-1d98-800b-81ca-91cbcb368b9f
	const onClick = (evt: MouseEvent) => {
		if (preventClickHack) evt.stopPropagation()
	}
	const onClickOrLong = (evt: MouseEvent, long: boolean) => {
		DEBUG(`BULLET ${long ? 'LONG' : 'CLICK'}`, evt)
		if (readOnly()) return
		if (evt.button === 0 && block.isTodo && !long) {
			evt.stopPropagation()
			evt.stopImmediatePropagation()
			evt.preventDefault()
			block.setTodoDone(!block.isTodoDone)
			preventClickHack = true
			setTimeout(() => {
				preventClickHack = false
			}, 0)
		}
	}
	onMount(() => onClickOrLongPress(bulletIconRef, () => onClickOrLong)) // HACK: https://github.com/solidjs/solid/discussions/722
	const IconID = `BulletMenu_${blockID}`
	return (
		<sl-dropdown hoist placement='bottom-start' ref={triggerRef} {...restProps}>
			{/* <Show when={restProps.onlyShowOnHover}>
				<style>
				  {}
				</style>
			</Show> */}
			<Iconify
				id={IconID}
				slot='trigger'
				ref={bulletIconRef}
				size={6}
				class={classNames(
					restProps.onlyShowOnHover && 'onlyShowOnHover mt-2',
					!readOnly() && 'drag-handle cursor-grab',
					block.isReply && hasKids() && 'rotate-180',
				)}
				name={restProps.onlyShowOnHover ? 'dots-three-circle' : props.iconProps?.name ?? 'dot-bold'}
				scale={restProps.onlyShowOnHover ? 88 : props.iconProps?.scale ?? 150}
				customSVG={props.iconProps?.icon}
				flex='shrink-0'
				on:click={!readOnly() && onClick} // (i) `on:` will attach a proper listener where the event can be cancelled - https://docs.solidjs.com/concepts/components/event-handlers#event-delegation-considerations
				onAuxClick={(e) => {
					if (e.button === 1) {
						e.preventDefault()
						focusViewOnBlock({ id: blockID }, locnav)
					}
				}}
				onContextMenu={(e) => {
					if (isTouchDevice()) return
					e.preventDefault()
					e.stopPropagation()
					e.target.parentElement.show()
				}}
			/>

			<sl-menu
				class='bullet-menu menu-tight'
				onsl-select={onSelection}
				ref={menuRef}
			>
				<Show when={!readOnly()}>
					{/* <sl-menu-item> */}
					<FlexBetween>
						{/* //TODO get highligting on roll over better */}
						<sl-menu-item class='-tight' value='outdent'>
							<Iconify class='mr-1' name='text-outdent' scale={120} slot='prefix' />
							<span>Outdent</span>
						</sl-menu-item>
						<sl-menu-item class='-tight -nosub' value='indent'>
							<span>Indent</span>
							<Iconify class='ml-1' name='text-indent' scale={120} slot='suffix' />
						</sl-menu-item>
					</FlexBetween>
				</Show>

				<sl-menu-item class='-tight' value='focus'>
					<Iconify name='arrows-in-cardinal-bold' scale={120} slot='prefix' />
					Zoom To
					<div text-xs mt--1 opacity-60>Middle click</div>
				</sl-menu-item>
				<Show when={!readOnly()}>
					<sl-menu-item class='-tight' value='delete'>
						<Iconify name='trash-bold' scale={120} slot='prefix' />
						Delete
						{' '}
						{/* TODO: "Remove" when the block has other placements */}
					</sl-menu-item>
				</Show>
				<sl-divider />
				{/* <sl-menu-item class="-tight" value={onCopyLink}>Copy note3:// link</sl-menu-item> */}
				<sl-menu-item class='-tight' value='copyID'>Copy ID</sl-menu-item>
				<sl-menu-item class='-tight' value='copyLink'>Copy Link</sl-menu-item>
				<sl-menu-item class='-tight' value='copyShareLink'>Copy Share Link</sl-menu-item>
				<sl-menu-item class='-tight'>
					Copy Content
					<sl-menu slot='submenu'>
						<sl-menu-item class='-tight' value='copyContent' data-handler-param='html'>
							Copy html ul tag
						</sl-menu-item>
						<sl-menu-item class='-tight' value='copyContent' data-handler-param='md'>
							Copy md (for pasting into logseq, zettlr etc)
						</sl-menu-item>
						<sl-menu-item class='-tight' value='copyContent' data-handler-param='opml'>
							Copy OPML (for pasting into WF, note3, etc)
						</sl-menu-item>
					</sl-menu>
				</sl-menu-item>
				<sl-divider />
				<Show when={!readOnly()}>
					<Show when={block.type !== 'smartlist'}>
						<sl-menu-item class='-tight' value='createSmartlist'>
							<Iconify name='list-magnifying-glass' scale={120} slot='prefix' />
							Create smartlist
						</sl-menu-item>
					</Show>
					<sl-menu-item class='-tight' value='reply'>
						<Iconify name='arrow-bend-down-right-bold' slot='prefix' />
						Reply
					</sl-menu-item>
					<Show when={appSettings.homeBlock}>
						<sl-menu-item class='-tight' value='addToHome'>
							<Iconify class='mr-1' name='list-plus' scale={120} slot='prefix' />
							<span>Add To Home</span>
						</sl-menu-item>
					</Show>
				</Show>
				<sl-menu-item class='-tight' value='settings'>
					<Iconify class='mr-1' name='gear-bold' scale={120} />
					Block Settings
				</sl-menu-item>
				<sl-menu-item class='-tight' value='history'>
					<Iconify name='clock-counter-clockwise-bold' scale={85} />
					History
				</sl-menu-item>
			</sl-menu>
		</sl-dropdown>
	)
}

function selectionHandlersForBulletMenu(setShareChooserOpen, setOnShareSelect, showBlockSettings) {
	const rawThread = useRawThread()
	const currentThread = useCurrentThread()

	const blockContext = useBlockContext()
	const relation = blockContext.relationToParent && useRelation(blockContext.relationToParent)
	const { parentContext } = blockContext

	const grandParentRelID = parentContext?.relationToParent ?? null
	// const grandParentVM = grandParentID ? BlockVM.get(grandParentID, rawDS) : null
	const grandParentRelVM = useRel(grandParentRelID, currentThread)
	const grandParentID = grandParentRelVM?.childOf

	const blockID = blockContext.id
	const location = useLocation()
	const navigator = useNavigate()
	const appSettings = useAppSettings()
	const onCopyLink = (evt: MouseEvent) => {
		DEBUG('copyLink', evt)
		const pub = useAgent().w3NamePublic // TODO: smart-select pub & UX for other cases
		// const n3url = `note3://publication/${pub}/?focus=${blockID}`
		const n3url = makeNote3Url({ pub, block: blockID })
		DEBUG('Note3 url', n3url)
		copyToClipboard(n3url)
	}

	const onReply = (evt: MouseEvent) => {
		const blkVM = useBlk(blockID, currentThread)

		const quotedContent = blkVM.selectionText ? `>${blkVM.selectionText}` : ''
		const added = addBlock({ thread: useCurrentThread(), asChildOf: blockID, content: quotedContent })
		const newBlkVM = useBlk(added, currentThread)
		VERBOSE('new reply block', added, { blkVM, newBlkVM, selection: blkVM.selectionText })
		const currentRelation = newBlkVM.currentRelation
		const replyApplog = {
			en: currentRelation.en,
			at: REL.isReply,
			vl: true,
		}
		DEBUG('new block as reply', replyApplog, added, { blkVM, newBlkVM, currentRelation })
		insertApplogs(currentThread, [replyApplog])
	}

	const onCopyShareLink = (evt: MouseEvent, mode: 'opml' | 'md' | 'html' = 'opml') => {
		DEBUG('opening share chooser for', blockID)

		const onSelect = (selEvt) => {
			DEBUG(blockID, selEvt)
			const share = selEvt.detail.item.value
			DEBUG(blockID, 'selected', share)
			const n3url = makeNote3Url({ pub: share, block: blockID, previewPub: true }) // HACK:use preview until ?pub= UX is better
			DEBUG('Note3 url', n3url)
			copyToClipboard(n3url)
			setShareChooserOpen(false)
		}
		setOnShareSelect(() => onSelect)
		setShareChooserBlockID(blockID)
		setShareChooserOpen(true)
	}
	const onCopyContent = (evt: MouseEvent, mode: 'opml' | 'md' | 'html' = 'opml') => {
		const formattedContent = mode === 'opml'
			? getRecursiveKidsOPML(blockID)
			: mode === 'md'
				? getRecursiveKidsJSON(blockID, 'md')
				: getRecursiveKidsJSON(blockID, 'html')
		DEBUG('Note3 content', blockID, { evt, formattedContent })
		copyToClipboard(formattedContent)
	}

	function createSmartlist() {
		const block = useBlk(blockID, rawThread)
		block.toggleSmartlist()
	}

	const settings = () => {
		DEBUG('show settings', blockID)
		showBlockSettings()
	}
	const addToHome = () => {
		if (!appSettings.homeBlock) return WARN('no homeBlock set')
		const addRelationLogs = getAddBlockRelationLogs({
			thread: currentThread,
			asChildOf: appSettings.homeBlock,
			blockID,
			focus: true,
			bottom: true,
		})
		DEBUG({ addRelationLogs })
		insertApplogs(currentThread, addRelationLogs)
	}
	const returnHandlers = {
		copyID: (_evt: MouseEvent) => copyToClipboard(blockID),
		copyLink: onCopyLink,
		copyShareLink: onCopyShareLink,
		copyContent: onCopyContent,
		reply: onReply,
		history: () => blockContext.setPanel({ type: 'history' }),
		focus: () => focusViewOnBlock({ id: blockID }, { location, navigate: navigator }),
		delete: () => removeBlockRelAndMaybeDelete(currentThread, blockID, relation?.get().en),
		indent: () => indentBlk(currentThread, relation?.get()),
		outdent: () => outdentBlk(currentThread, relation?.get(), grandParentID),
		addToHome,
		settings,
		createSmartlist,
	} as const

	return returnHandlers
}
