/* Dependencies */
import React, { forwardRef, useState } from 'react'
import {
	KeyboardTypeOptions,
	StyleProp,
	StyleSheet, TextInput as ReactTextInput, TextStyle
} from 'react-native'

/* Libraries */
import { TextInput, useTheme } from 'react-native-paper'

/* Functions */
import { delayedAlert } from '../../functions'
import { executeSqlAsync } from '../../functions/database'

/* Types */
type Props<T> = React.ComponentProps<typeof TextInput> & {
	/**
	 * @description If true, the text input will be disabled
	 * @default false
	 */
	disabled?: boolean
	error?: boolean
	field: string
	label: string
	navigation: any
	/**
	 * @description Function to be called when the text changes
	 */
	onChange?: (value: string) => void
	onSelect?: (value: T | null) => void
	onBlur?: () => void
	readOnly?: boolean
	requires?: boolean | string
	requiresMessage?: string
	rootScreen?: string
	screen: string
	setField: React.Dispatch<React.SetStateAction<string>>
	style?: StyleProp<TextStyle>
	/**
	 * @description Keyboard type
	 * @default 'numeric'
	 */
	type?: KeyboardTypeOptions
	valid: string
	where?: string
}

const View = forwardRef<ReactTextInput, Props<unknown>>((props, forwardedRef) => {
	let {
		field,
		label,
		navigation,
		onChange,
		onSelect,
		onBlur,
		readOnly,
		requires,
		requiresMessage = 'Os pré-requisitos não foram atendidos',
		rootScreen,
		screen,
		setField,
		type = 'numeric',
		valid,
		where,
		style,
		disabled,
		error,
		...rest
	} = props

	/* Styles */
	const { colors } = useTheme()
	const styles = StyleSheet.create({
		container: {
			flex: 1,
			margin: 5
		}
	})

	/* States */
	const [isFocused, setIsFocused] = useState(false)

	/* Functions */
	async function blur(): Promise<void> {
		if (valid && field) {
			if (requires === undefined || requires) {
				try {
					const { rows } = await executeSqlAsync(valid)
					if (rows.item(0)) {
						if (rows.item(0).str) {
							setField(`${rows.item(0).cod} - ${rows.item(0).str}`)
						} else {
							setField(`${rows.item(0).cod}`)
						}
						onSelect?.(rows.item(0))
					} else {
						setField('')
						onSelect?.(null)
						delayedAlert('Código não encontrado')
					}
				} catch (error) {
					const { message = 'Erro desconhecido' } = error as Error
					delayedAlert(message)
				}
			} else {
				setField('')
				onSelect?.(null)
				delayedAlert(requiresMessage)
				setIsFocused(false)
			}
		}
		setIsFocused(false)
	}

	function onChangeText(value: string): void {
		setField(value)
		onChange?.(value)
	}

	function onOpenView() {
		if (screen) {
			if (requires === undefined || requires) {
				navigation.navigate(screen, {
					root: rootScreen,
					field: label,
					getWhere: where
				})
			} else {
				delayedAlert(requiresMessage)
			}
		} else {
			delayedAlert('Visualização não selecionada')
		}
	}

	return (
		<TextInput
			editable={readOnly}
			error={error}
			disabled={disabled}
			keyboardType={type}
			label={label}
			mode={'flat'}
			onBlur={() => {
				onBlur?.()
				blur()
			}}
			onChangeText={onChangeText}
			onFocus={() => setIsFocused(true)}
			ref={forwardedRef}
			right={
				disabled ? null : (
					<TextInput.Icon
						hasTVPreferredFocus={undefined} // TODO: Fix this
						tvParallaxProperties={undefined} // TODO: Fix this
						color={isFocused ? colors.primary : 'rgb(100,100,100)'}
						name={field ? 'close' : 'magnify'}
						onPress={() => (field ? onChangeText('') : onOpenView())}
						size={28}
					/>
				)
			}
			style={style ?? styles.container}
			value={field}
			{...rest}
		/>
	)

	// infer a generics "T" and keep displayName of the component
}) as <T>(props: Props<T> & { ref?: React.Ref<ReactTextInput> }) => JSX.Element

// EditView.displayName = 'Edit.View'

export default View
