import React, { ChangeEvent, FC, FocusEvent, KeyboardEvent, MouseEvent, RefObject } from 'react'
import styled from 'styled-components'

export interface CaptchaProps {
	length?: number
	value?: string
	onChange?: (value: string) => void
}

const StyledWrapper = styled.div`
  display: flex;
	flex-direction: row;
	gap: 14px;
`
const StyledInputWrapper = styled.div`
  flex: 0 0 40px;
	height: 48px;
`
const StyledInput = styled.input`
  width: 100%;
  height: 48px;
  padding: 8px;
  font-size: 28px;
	font-weight: 500;
  line-height: 32px;
  text-align: center;
  border-radius: 2px;
  box-sizing: border-box;
  border: 2px solid #000022;

  &:focus {
		text-decoration: underline;
    outline: 2px solid ${({ theme }) => theme.brandPrimary};
  }
`

function textSelect(element: HTMLInputElement): void {
	const start = 0;
	const end = element.value.length;
	element.setSelectionRange(start, end);
	element.focus();
}

export const Captcha: FC<CaptchaProps> = ({ value, onChange, length = 6 }) => {
	const inputDomRefs: RefObject<HTMLInputElement>[] = Array.from({ length }, () => React.createRef<HTMLInputElement>())
	const getCode = (index: number): string => {
		return value && value.length > index ? value[index] : ''
	}
	const getNewValue = (newValue: string, index: number) => {
		const oldValue = Array.from({ length }, (_, i) => getCode(i))
		oldValue[index] = newValue
		return oldValue.map(v => v || ' ').join('').trimEnd()
	}
	const focusOn = (index: number, select?: boolean) => {
		if (inputDomRefs[index] && inputDomRefs[index].current) {
			inputDomRefs[index].current?.focus()
			if (select) {
				textSelect(inputDomRefs[index].current!)
			}
		}
	}
	const handleFocus =  (e: FocusEvent<HTMLInputElement>) => {
		textSelect(e.target)
	}
	const handleClick = (e: MouseEvent<HTMLInputElement>) => {
		textSelect(e.target as HTMLInputElement)
	}
	const handleChange = (index: number) => (e: ChangeEvent<HTMLInputElement>) => {
		const value = e.target.value.trim()
		if (onChange) {
			onChange(getNewValue(value, index))
		}
		textSelect(e.target)
		if (value) {
			focusOn(index + 1)
		}
	}
	const handleKeydown = (index: number) => (e: KeyboardEvent<HTMLInputElement>) => {
		switch (e.key) {
			case 'Backspace':
				// @ts-ignore
				if (e.target.value === "") {
					e.stopPropagation();
					focusOn(index - 1)
				}
				break;
			case 'ArrowLeft':
			case 'ArrowUp':
				e.stopPropagation();
				if (inputDomRefs[index - 1]) {
					focusOn(index - 1)
				} else {
					focusOn(index)
				}
				break;
			case 'ArrowRight':
			case 'ArrowDown':
				e.stopPropagation();
				if (inputDomRefs[index + 1]) {
					focusOn(index + 1)
				} else {
					focusOn(index)
				}
				break;
			default:
				textSelect(e.target as HTMLInputElement)
				break;
		}
	}
	return (
		<StyledWrapper>
			{
				Array.from({ length }, () => "").map((_, index) => {
					return (
						<StyledInputWrapper key={index}>
							<StyledInput
								type="text"
								value={getCode(index)}
								ref={inputDomRefs[index]}
								onFocus={handleFocus}
								onClick={handleClick}
								onChange={handleChange(index)}
								onKeyDown={handleKeydown(index)}
								spellCheck="false"
								autoComplete="false"
								autoCorrect="false"
								autoCapitalize="off"
							/>
						</StyledInputWrapper>
					)
				})
			}
		</StyledWrapper>
	)
}
