// Import types from type-fest first
import type { DefaultPathsOptions, PathsOptions } from 'type-fest/source/paths'

// Import types from local types file
import type {
	Path,
	BaseBagelField,
	InputBagelField,
	SelectBagelField,
	ArrayBagelField,
	ArrayFieldVal,
	Attributes,
	BglFormSchemaT,
	FieldByP,
	ShallowBglFormSchemaT,
	UploadInputProps
} from '../types/BagelForm'

// Local type definitions for internal use only
interface IconType { name: string }
interface AutoFillField { name: string }
interface InputTypeHTMLAttribute { type: string }
type MaybeRefOrGetter<T> = T | (() => T) | { value: T }

export interface InputOptions<
	T,
	P extends Path<T>
> extends Partial<BaseBagelField<T, P>> {
	defaultValue?: string | number
	autocomplete?: AutoFillField
	helpText?: string
	title?: string
}

export interface DateOptions<T, K extends Path<T>> extends InputOptions<T, K> {
	enableTime?: boolean
	mode?: 'day' | 'month' | 'year'
	locale?: string
	timezone?: string
}

export interface TextInputOptions<T, K extends Path<T>> extends InputOptions<T, K> {
	type?: InputTypeHTMLAttribute['type']
	pattern?: string
	multiline?: boolean
	autoheight?: boolean
	code?: boolean
	rows?: number | string
	icon?: IconType
	iconStart?: IconType
}

export interface SlctInputOptions<T, K extends Path<T>> extends InputOptions<T, K> {
	searchable?: boolean
	multiselect?: boolean
	clearable?: boolean
	placeholder?: string
}

export interface NumFieldOptions<T, K extends Path<T>> extends InputOptions<T, K> {
	max?: number
	min?: number
	step?: number
	layout?: 'default' | 'vertical' | 'horizontal'
	padZero?: number
	center?: boolean
	useGrouping?: boolean
}

export interface RichTextOptions<T, P extends Path<T>> extends InputOptions<T, P> {
	height?: number | string
	basic?: boolean
	simple?: boolean
	debug?: boolean
	// Manual hide options
	hideToolbar?: boolean
	hideInlineToolbar?: boolean
	hideImages?: boolean
	hideVideos?: boolean
	hideEmbed?: boolean
	hideTables?: boolean
	hideAlignment?: boolean
	hideDirections?: boolean
	hideH5H6?: boolean
	// Simple array-based hide option
	hide?: string[]
	// Control autofocus behavior
	autofocus?: boolean
	// Text color
	textColor?: string
	// Font size
	fontSize?: number | string
}

export interface TelInputOptions<T, P extends Path<T>> extends InputOptions<T, P> {
	pattern?: string
	autocomplete?: AutoFillField
	onlyCountries?: string[]
	defaultCountry?: string
	excludeCountries?: string[]
}

export function getBaseField<T, P extends Path<T, PO>, PO extends PathsOptions = DefaultPathsOptions>(
	id?: P,
	labelOrRest: string | Partial<BaseBagelField<T, P>> = {},
	rest: Partial<BaseBagelField<T, P>> = {}
): BaseBagelField<T, P, PO> {
	if (typeof labelOrRest === 'object') { return { id, ...labelOrRest } }
	return { id, label: labelOrRest, ...rest }
}

export function richText<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: RichTextOptions<T, P>,
): BaseBagelField<T, P, PO> {
	return {
		$el: 'richtext',
		class: options?.class,
		required: options?.required,
		id,
		label,
		helptext: options?.helpText,
		disabled: options?.disabled,
		defaultValue: options?.defaultValue,
		vIf: options?.vIf,
		transform: options?.transform,
		placeholder: options?.placeholder,
		attrs: {
			height: options?.height,
			basic: options?.basic,
			simple: options?.simple,
			debug: options?.debug,
			hideToolbar: options?.hideToolbar,
			hideInlineToolbar: options?.hideInlineToolbar,
			hideImages: options?.hideImages,
			hideVideos: options?.hideVideos,
			hideEmbed: options?.hideEmbed,
			hideTables: options?.hideTables,
			hideAlignment: options?.hideAlignment,
			hideDirections: options?.hideDirections,
			hideH5H6: options?.hideH5H6,
			hide: options?.hide,
			autofocus: options?.autofocus,
			textColor: options?.textColor,
			fontSize: options?.fontSize,
			autocomplete: options?.autocomplete,
		},
	}
}

export function txtField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: TextInputOptions<T, P>,
): InputBagelField<T, P, PO> {
	return {
		$el: 'text',
		id,
		label,
		class: options?.class,
		required: options?.required,
		placeholder: options?.placeholder,
		helptext: options?.helptext,
		disabled: options?.disabled,
		defaultValue: options?.defaultValue,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			title: options?.title,
			autocomplete: options?.autocomplete,
			pattern: options?.pattern,
			multiline: options?.multiline,
			autoheight: options?.autoheight,
			code: options?.code,
			rows: options?.rows,
			icon: options?.icon,
			iconStart: options?.iconStart,
			type: options?.type,
		},
	}
}

// import type { Option } from '@bagelink/vue'

// type OptionsSource = Option[] | ((query: string) => Promise<Option[]>)

export function selectField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: any,
	fieldOptions?: SlctInputOptions<T, P>,
): SelectBagelField<T, P, PO> {
	return {
		$el: 'select',
		id,
		label,
		class: fieldOptions?.class,
		required: fieldOptions?.required,
		helptext: fieldOptions?.helptext,
		disabled: fieldOptions?.disabled,
		defaultValue: fieldOptions?.defaultValue,
		vIf: fieldOptions?.vIf,
		transform: fieldOptions?.transform,
		placeholder: fieldOptions?.placeholder,
		options,
		attrs: {
			...fieldOptions?.attrs,
			title: fieldOptions?.title,
			searchable: fieldOptions?.searchable,
			multiselect: fieldOptions?.multiselect,
			clearable: fieldOptions?.clearable,
		},
	}
}

export const slctField = selectField

interface CheckInputOptions<T, K extends Path<T>> extends Omit<InputOptions<T, K>, 'defaultValue'> {
	value?: string | number | boolean
	defaultValue?: string | number | boolean
}

export function checkField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: CheckInputOptions<T, P>,
): BaseBagelField<T, P, PO> {
	return {
		$el: 'check',
		id,
		label,
		class: options?.class,
		required: options?.required,
		helptext: options?.helptext,
		disabled: options?.disabled,
		defaultValue: options?.defaultValue,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			...options?.attrs,
			value: options?.value,
		},
	}
}

interface EmailInputOptions<
	T,
	P extends Path<T>
> extends InputOptions<T, P> {
	autocorrect?: boolean
	serverValidate?: boolean
	preventFakeEmails?: boolean
	pattern?: string
}

export function emailField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(id?: P, label?: string, options?: EmailInputOptions<T, P>): BaseBagelField<T, P, PO> {
	return {
		$el: 'email',
		id,
		label,
		class: options?.class,
		required: options?.required,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			title: options?.title,
			autocorrect: options?.autocorrect,
			serverValidate: options?.serverValidate,
			preventFakeEmails: options?.preventFakeEmails,
			pattern: options?.pattern,
		},
	}
}

export function dateField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: DateOptions<T, P>,
): BaseBagelField<T, P, PO> {
	return {
		$el: 'date',
		class: options?.class,
		required: options?.required,
		id,
		disabled: options?.disabled,
		label,
		...(options?.defaultValue !== undefined && { defaultValue: options.defaultValue }),
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			title: options?.title,
			disabled: options?.disabled,
			autocomplete: options?.autocomplete,
			enableTime: options?.enableTime,
			mode: options?.mode,
			locale: options?.locale,
			timezone: options?.timezone,
		},
	}
}

export function numField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: NumFieldOptions<T, P>,
): BaseBagelField<T, P, PO> {
	return {
		$el: 'number',
		class: options?.class,
		required: options?.required,
		defaultValue: options?.defaultValue,
		id,
		label,
		disabled: options?.disabled,
		placeholder: options?.placeholder,
		helptext: options?.helptext,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			title: options?.title,
			autocomplete: options?.autocomplete,
			step: options?.step,
			min: options?.min,
			max: options?.max,
			layout: options?.layout,
			padZero: options?.padZero,
			center: options?.center,
			useGrouping: options?.useGrouping,
		},
	}
}

export function frmRow<
	T,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	...children: Array<BaseBagelField<T, any, PO>>
): { $el: string, class: string, children: Array<BaseBagelField<T, any, PO>> } {
	return {
		$el: 'div',
		class: 'flex gap-1 m_block align-items-end',
		children,
	}
}

export interface UploadOptions<T, K extends Path<T>> extends Omit<UploadInputProps, 'id'>, InputOptions<T, K> {}

export function uploadField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: UploadOptions<T, P>,
): BaseBagelField<T, P, PO> {
	return {
		$el: 'upload',
		id,
		label,
		class: options?.class,
		required: options?.required,
		helptext: options?.helptext,
		disabled: options?.disabled,
		defaultValue: options?.defaultValue,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			...options,
		},
	}
}

interface RangeOptions<T, K extends Path<T>> extends InputOptions<T, K> {
	min?: number
	max?: number
	step?: number
	rtl?: boolean
	multiRange?: boolean
	formatValue?: (value: number) => string
}

export function rangeField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: RangeOptions <T, P>
): BaseBagelField<T, P, PO> {
	return {
		$el: 'range',
		id,
		label,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			autocomplete: options?.autocomplete,
			min: options?.min,
			max: options?.max,
			step: options?.step,
			rtl: options?.rtl,
			multiRange: options?.multiRange,
			formatValue: options?.formatValue,
		},
	}
}

export function bglForm<T>(idOrField?: string | FieldByP<T, Path<T>>, ...schema: FieldByP<T, Path<T>>[]) {
	if (typeof idOrField === 'string') {
		return {
			$el: 'bagelform',
			id: idOrField,
			attrs: {
				schema: [idOrField, ...schema],
			},
		}
	}
	return {
		$el: 'bagelform',
		attrs: {
			schema: [idOrField, ...schema]
		},
	}
}

export function telField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: TelInputOptions<T, P>
): BaseBagelField<T, P, PO> {
	return {
		$el: 'tel',
		id,
		label,
		class: options?.class,
		required: options?.required,
		placeholder: options?.placeholder,
		helptext: options?.helptext,
		disabled: options?.disabled,
		defaultValue: options?.defaultValue,
		vIf: options?.vIf,
		transform: options?.transform,
		attrs: {
			...options?.attrs,
			title: options?.title,
			pattern: options?.pattern,
			autocomplete: options?.autocomplete,
		},
	}
}

export function colorField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id?: P,
	label?: string,
	options?: { [key: string]: any }
): BaseBagelField<T, P, PO> {
	return {
		$el: 'color',
		id,
		label,
		vIf: options?.vIf,
		attrs: options,
		class: options?.class,
		transform: options?.transform,
	}
}

export function findBglFieldById<T>(id: string, _schema: ShallowBglFormSchemaT<T>): FieldByP<T, Path<T>> | undefined {
	for (const field of _schema) {
		if (field.id === id) { return field as FieldByP<T, Path<T>> | undefined }
		if (field.children && Number(field.children.length) > 0) {
			const fieldChildren = field.children.filter(
				c => typeof c === 'object' && '$el' in c
			)
			const child = findBglFieldById(id, fieldChildren as ShallowBglFormSchemaT<T>)
			if (child) { return child as FieldByP<T, Path<T>> | undefined }
		}
	}
	return undefined
}

export interface ArrayAttrs<T, P extends Path<T>> extends Attributes<T, P> {
	delete?: boolean
	add?: boolean
	schema?: MaybeRefOrGetter<BglFormSchemaT<ArrayFieldVal<T, P>>>
	type?: ArrayType
}

export interface ArrayFieldOptions<T, K extends Path<T>> extends InputOptions<T, K>,	ArrayAttrs<T, K> {}

export type ArrayType = 'number' | 'text'

export function arrField<
	T,
	P extends Path<T, PO>,
	PO extends PathsOptions = DefaultPathsOptions,
>(
	id: P,
	label: string,
	schemaOrType: BglFormSchemaT<ArrayFieldVal<T, P>> | ArrayType,
	options?: ArrayFieldOptions<T, P>
): ArrayBagelField<T, P, PO> {
	const arraySpecificAttrs = (
		typeof schemaOrType === 'string'
			? { type: schemaOrType }
			: { schema: schemaOrType }
	)

	const attrs: ArrayAttrs<T, P> = {
		delete: true,
		add: true,
		...options,
		...arraySpecificAttrs,
	}

	return {
		label,
		id,
		class: options?.class,
		$el: 'array',
		vIf: options?.vIf,
		transform: options?.transform,
		attrs,
	}
}
// export function updateBagelSchemaWithErrorResponse<T>(
// 	schema: BglFormSchemaT<T>,
// 	invalidFieldId: Record<string, string[]>,
// ) {
// 	return schema.map((f) => {
// 				if (f.id === invalidFieldId) {
// 					f.class = 'bagel-input-error'
// 				}
// 				if (f.id === undefined && f.children) {
// 					f.children = f.children.map((c) => {
// 						if (c.id === invalidFieldId) {
// 							c.class = 'bagel-input-error'
// 						}
// 						return c
// 					})
// 				}
// 				return f
// 			})
// }

// Schema builder function that provides type context
export function createSchema<T, PO extends PathsOptions = DefaultPathsOptions>() {
	return {
		txtField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: TextInputOptions<T, P>
		) => txtField<T, P, PO>(id, label, options),

		selectField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: any,
			fieldOptions?: SlctInputOptions<T, P>
		) => selectField<T, P, PO>(id, label, options, fieldOptions),

		dateField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: DateOptions<T, P>
		) => dateField<T, P, PO>(id, label, options),

		telField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: TelInputOptions<T, P>
		) => telField<T, P, PO>(id, label, options),

		frmRow: (
			...children: Array<BaseBagelField<T, any, PO>>
		) => frmRow<T, PO>(...children),

		// Add other field functions as needed
		numField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: NumFieldOptions<T, P>
		) => numField<T, P, PO>(id, label, options),

		checkField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: CheckInputOptions<T, P>
		) => checkField<T, P, PO>(id, label, options),

		emailField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: EmailInputOptions<T, P>
		) => emailField<T, P, PO>(id, label, options),

		uploadField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: UploadOptions<T, P>
		) => uploadField<T, P, PO>(id, label, options),

		rangeField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: RangeOptions<T, P>
		) => rangeField<T, P, PO>(id, label, options),

		colorField: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: { [key: string]: any }
		) => colorField<T, P, PO>(id, label, options),

		richText: <P extends Path<T, PO>>(
			id?: P,
			label?: string,
			options?: RichTextOptions<T, P>
		) => richText<T, P, PO>(id, label, options),
	}
}

export function useForm() {
	return {
		txtField,
		selectField,
		checkField,
		dateField,
		numField,
		emailField,
		frmRow,
		uploadField,
		rangeField,
		bglForm,
		telField,
		colorField,
		arrField,
		richText,
		findBglFieldById,
		getBaseField,
		createSchema
	}
}
