import type { ElementField, IconType, Option, Path } from '@bagelink/vue'
import { Dropdown, ListItem } from '@bagelink/vue'
import { markRaw } from 'vue'

export type DefaultPathsOptions = Record<string, any>
export type PathsOptions = Record<string, any>

export type BaseElementField<T, PO extends PathsOptions = DefaultPathsOptions> = ElementField<T, PO>

export interface BtnElementOptions<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
> extends Partial<BaseElementField<T, PO>> {
	text?: string
	variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'
	size?: 'sm' | 'md' | 'lg'
	disabled?: boolean
	loading?: boolean
	icon?: IconType
	iconPosition?: 'left' | 'right'
	href?: string
	target?: '_blank' | '_self' | '_parent' | '_top'
}

export interface PillElementOptions<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
> extends Partial<BaseElementField<T, PO>> {
	color?: string
	icon?: IconType
}

export interface TxtElementOptions<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
> extends Partial<BaseElementField<T, PO>> {
	text?: string
	tag?: 'p' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div'
	size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
	weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold'
	color?: string
	align?: 'left' | 'center' | 'right' | 'justify'
}

export interface ImgElementOptions<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
> extends Partial<BaseElementField<T, PO>> {
	src?: string
	alt?: string
	width?: number | string
	height?: number | string
	loading?: 'lazy' | 'eager'
	fit?: 'cover' | 'contain' | 'fill' | 'scale-down' | 'none'
	rounded?: boolean | 'sm' | 'md' | 'lg' | 'full'
	fallback?: string
}

export interface DropdownElementOptions<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
> extends Partial<BaseElementField<T, PO>> {
	options?: Option[] | (() => Option[])
	placeholder?: string
	searchable?: boolean
	multiselect?: boolean
	clearable?: boolean
	onSelect?: (value: any) => void
	onSearch?: (search: string) => any
}

export interface ListItemElementOptions<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
> extends Partial<BaseElementField<T, PO>> {
	id?: Path<T, PO>
	title?: string
	subtitle?: string
	icon?: IconType
	avatar?: string
	badge?: string | number
	actions?: Array<{ label: string, onClick: () => void, icon?: IconType }>
	clickable?: boolean
	divider?: boolean
}

// Magical button overloads with schema support
export function btn<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(options: BtnElementOptions<T, PO>): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, text: string): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, icon: IconType): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	id: P,
	text: string,
	options: BtnElementOptions<T, PO>
): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	id: P,
	icon: IconType,
	options: BtnElementOptions<T, PO>
): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	id: P,
	textOrIcon: string | IconType,
	options: BtnElementOptions<T, PO>
): BaseElementField<T, PO>
export function btn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	idOrOptions?: P | BtnElementOptions<T, PO>,
	textOrIcon?: string | IconType,
	options?: BtnElementOptions<T, PO>,
): BaseElementField<T, PO> {
	// Handle different overload patterns
	let id: Path<T, PO> | undefined
	let text: string = ''
	let icon: IconType | undefined
	let finalOptions: BtnElementOptions<T, PO> = {}

	if (typeof idOrOptions === 'object' && idOrOptions !== null) {
		// btn(options)
		finalOptions = idOrOptions
		const { id: optionId, text: optionText, icon: optionIcon } = finalOptions
		id = optionId as Path<T, PO> | undefined
		text = optionText ?? ''
		icon = optionIcon
	} else {
		// btn(id, ...) patterns
		id = idOrOptions
		if (textOrIcon != null) {
			// Check if textOrIcon is likely an icon vs text
			// Icons are typically: lowercase, contain hyphens/underscores, no spaces, shorter length
			const isLikelyIcon = typeof textOrIcon === 'string'
				&& textOrIcon.length <= 30
				&& !textOrIcon.includes(' ')
				&& (textOrIcon.includes('-')
					|| textOrIcon.includes('_')
					|| textOrIcon.length <= 12)
				&& textOrIcon === textOrIcon.toLowerCase()

			if (isLikelyIcon) {
				icon = textOrIcon as IconType
				if (options) {
					finalOptions = options
				}
			} else {
				text = textOrIcon
				if (options) {
					finalOptions = options
				}
			}
		}
	}

	return {
		$el: 'btn',
		id,
		class: finalOptions.class,
		vIf: finalOptions.vIf,
		style: finalOptions.style,
		onClick: finalOptions.onClick,
		attrs: {
			value: text || (finalOptions.text ?? '') || '',
			variant: finalOptions.variant,
			size: finalOptions.size,
			disabled: finalOptions.disabled,
			loading: finalOptions.loading,
			icon: icon ?? finalOptions.icon,
			iconPosition: finalOptions.iconPosition,
			href: finalOptions.href,
			target: finalOptions.target,
		},
	}
}

export function getBaseElementField<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	elementType: string,
	id?: Path<T, PO>,
	options: Partial<BaseElementField<T, PO>> = {}
): BaseElementField<T, PO> {
	return {
		$el: elementType,
		id,
		class: options.class,
		vIf: options.vIf,
		style: options.style,
		attrs: options.attrs || {},
		onClick: options.onClick,
	}
}

// Icon button shorthand
export function iconBtn<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	id?: P,
	icon?: IconType,
	options?: BtnElementOptions<T, PO>,
): BaseElementField<T, PO> {
	if (icon != null && id != null) {
		return btn(id, icon, options || {})
	}
	return btn({ id, icon, ...options } as BtnElementOptions<T, PO>)
}

// Magical text overloads with schema support
export function txt<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(options: TxtElementOptions<T, PO>): BaseElementField<T, PO>
export function txt<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P): BaseElementField<T, PO>
export function txt<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, text: string): BaseElementField<T, PO>
export function txt<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	id: P,
	text: string,
	tag: 'p' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div'
): BaseElementField<T, PO>
export function txt<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, text: string, options: TxtElementOptions<T, PO>): BaseElementField<T, PO>
export function txt<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	idOrOptions?: P | TxtElementOptions<T, PO>,
	text?: string,
	tagOrOptions?: string | TxtElementOptions<T, PO>,
): BaseElementField<T, PO> {
	// Handle different overload patterns
	let id: Path<T, PO> | undefined
	let finalOptions: TxtElementOptions<T, PO> = {}

	if (typeof idOrOptions === 'object' && idOrOptions !== null) {
		// txt(options)
		finalOptions = idOrOptions
		const { id: optionId } = finalOptions
		id = optionId as Path<T, PO> | undefined
	} else {
		// txt(id, ...) patterns
		id = idOrOptions
		if (text != null) {
			if (typeof tagOrOptions === 'string') {
				// txt(id, text, tag)
				finalOptions = { tag: tagOrOptions as any, text }
			} else if (tagOrOptions) {
				// txt(id, text, options)
				finalOptions = { ...tagOrOptions, text }
			} else {
				finalOptions = { text }
			}
		}
	}

	return {
		$el: finalOptions.tag || 'p',
		id,
		class: finalOptions.class,
		vIf: finalOptions.vIf,
		style: finalOptions.style,
		attrs: {
			text: finalOptions.text ?? '',
			size: finalOptions.size,
			weight: finalOptions.weight,
			color: finalOptions.color,
			align: finalOptions.align,
		},
		transform: finalOptions.transform,
	}
}

// Magical image overloads with schema support
export function img<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(options: ImgElementOptions<T, PO>): BaseElementField<T, PO>
export function img<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P): BaseElementField<T, PO>
export function img<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, src: string): BaseElementField<T, PO>
export function img<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, src: string, alt: string): BaseElementField<T, PO>
export function img<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(id: P, src: string, options: ImgElementOptions<T, PO>): BaseElementField<T, PO>
export function img<
	T = any,
	P extends Path<T, PO> = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	idOrOptions?: P | ImgElementOptions<T, PO>,
	src?: string,
	altOrOptions?: string | ImgElementOptions<T, PO>,
): BaseElementField<T, PO> {
	// Handle different overload patterns
	let id: Path<T, PO> | undefined
	let finalOptions: ImgElementOptions<T, PO> = {}

	if (typeof idOrOptions === 'object' && idOrOptions !== null) {
		// img(options)
		finalOptions = idOrOptions
		const { id: optionId } = finalOptions
		id = optionId as Path<T, PO> | undefined
	} else {
		// img(id, ...) patterns
		id = idOrOptions
		if (src != null) {
			if (typeof altOrOptions === 'string') {
				// img(id, src, alt)
				finalOptions = { alt: altOrOptions }
			} else if (altOrOptions) {
				// img(id, src, options)
				finalOptions = altOrOptions
			}
		}
	}

	return {
		$el: 'img',
		id,
		class: finalOptions.class,
		vIf: finalOptions.vIf,
		style: finalOptions.style,
		transform: finalOptions.transform,
		attrs: {
			alt: finalOptions.alt,
			width: finalOptions.width,
			height: finalOptions.height,
			loading: finalOptions.loading,
			fit: finalOptions.fit,
			rounded: finalOptions.rounded,
			fallback: finalOptions.fallback,
		},
	}
}

export function pill<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(options: PillElementOptions<T, PO>): BaseElementField<T, PO> {
	return {
		$el: 'pill',
		id: options?.id,
		class: options?.class,
		vIf: options?.vIf,
		style: options?.style,
		attrs: options?.attrs || {},
	}
}

export function dropdown<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	...args: Array<DropdownElementOptions<T, PO> | BaseElementField<T, PO>>
): BaseElementField<T, PO> {
	let opts: DropdownElementOptions<T, PO> | undefined
	let children: BaseElementField<T, PO>[] = []

	if (args.length > 0) {
		const firstArg = args[0] as DropdownElementOptions<T, PO> | BaseElementField<T, PO>
		if (
			typeof firstArg === 'object'
			&& firstArg !== null
			&& ('$el' in (firstArg as Record<string, unknown>))
		) {
			children = args as BaseElementField<T, PO>[]
		} else {
			opts = firstArg as DropdownElementOptions<T, PO>
			children = args.slice(1) as BaseElementField<T, PO>[]
		}
	}

	const attrs: Record<string, unknown> = {}
	if (opts?.attrs) { Object.assign(attrs, opts.attrs) }
	if (opts) {
		if (opts.options != null) { attrs.options = opts.options }
		if (opts.placeholder != null) { attrs.placeholder = opts.placeholder }
		if (opts.searchable != null) { attrs.searchable = opts.searchable }
		if (opts.multiselect != null) { attrs.multiselect = opts.multiselect }
		if (opts.clearable != null) { attrs.clearable = opts.clearable }
		if (opts.onSelect != null) { attrs.onSelect = opts.onSelect }
		if (opts.onSearch != null) { attrs.onSearch = opts.onSearch }
	}

	return {
		$el: markRaw(Dropdown),
		class: opts?.class,
		vIf: opts?.vIf,
		style: opts?.style,
		attrs,
		children,
	}
}

// ListItem element function following BagelForm pattern
export function listItem<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	title?: string,
	options?: ListItemElementOptions<T, PO>,
): BaseElementField<T, PO> {
	return {
		$el: markRaw(ListItem),
		id: options?.id,
		class: options?.class,
		vIf: options?.vIf,
		style: options?.style,
		onClick: options?.onClick,
		attrs: {
			thin: true,
			title: title ?? options?.title ?? '',
			subtitle: options?.subtitle,
			icon: options?.icon,
			avatar: options?.avatar,
			badge: options?.badge,
			actions: options?.actions,
			clickable: options?.clickable,
			divider: options?.divider,
		},
	}
}

// Container element function following BagelForm pattern
export function container<
	T = any,
	PO extends PathsOptions = DefaultPathsOptions
>(
	id?: Path<T, PO>,
	children?: BaseElementField<T, any>[],
	options?: Partial<BaseElementField<T, PO>>,
): BaseElementField<T, PO> {
	return {
		$el: 'div',
		id,
		class: options?.class ?? 'flex gap-2',
		vIf: options?.vIf,
		style: options?.style,
		attrs: options?.attrs || {},
		children: children as any,
	}
}

export function findElementById<T>(
	id: string,
	elements: BaseElementField<T, any>[]
): BaseElementField<T, any> | undefined {
	for (const element of elements) {
		if (element.id === id) { return element }
		if (element.children && element.children.length > 0) {
			const child = findElementById(id, element.children)
			if (child) { return child }
		}
	}
	return undefined
}

export function column<T = any, P extends Path<T, PO> = any, PO extends PathsOptions = DefaultPathsOptions>(
	id?: P,
	labelOrOptions?: string | Partial<BaseElementField<T, PO>>,
	options?: Partial<BaseElementField<T, PO>>,
): BaseElementField<T, PO> {
	let label: string | undefined
	if (typeof labelOrOptions === 'string') {
		label = labelOrOptions
	} else {
		options = labelOrOptions
	}

	return {
		$el: 'div',
		id,
		class: options?.class ?? 'column-class',
		vIf: options?.vIf,
		style: options?.style,
		transform: options?.transform,
		attrs: {
			...options?.attrs,
			label: label ?? options?.attrs?.label ?? '',
		},
		children: options?.children as any,
	}
}

export const col = column

export function useElements() {
	return {
		btn,
		iconBtn,
		txt,
		img,
		dropdown,
		listItem,
		container,
		findElementById,
		getBaseElementField,
		col,
		column,
	}
}
