import {FormValue} from "../../components/Form/types/FormValue";
import {FormInput} from "../../components/Form/types/FormInput";

const Validators = [
    {
        name: 'required',
        error: 'Dane pole jest wymagane',
        validator: (item: string): boolean => {
            return (item !== null && item !== '' && item !== 'false' && item !== 'null')
        },
    },
    {
        name: 'phone',
        error: 'Błędny numer telefonu',
        validator: (item: string): boolean => {
            const value = item.toString().replace(/ /g, '')

            return /[0-9]{9}/.test(value) && value.length === 9 && value !== '000000000'
        },
    },
    {
        name: 'email',
        error: 'Niepoprawny adres email',
        validator: (item: string): boolean => {
            return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
                item
            )
        },
    },
    {
        name: 'pesel',
        error: 'Niepoprawny numer pesel',
        validator: (item: string): boolean => {
            if (item.length == 11) {
                let arr = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
                let sum = 0;

                for (let i = 0; i < 10; i++) {
                    // @ts-ignore
                    sum += arr[i] * item[i];
                }

                sum = sum%10 == 0 ? 0 : 10-sum%10;
                // @ts-ignore
                return sum === parseInt(item[10]);
            }

            return false;
        },
    },
    {
        name: 'nip',
        error: 'Błędny NIP',
        validator: (item: string): boolean => {
            const numbers = [6, 5, 7, 2, 3, 4, 5, 6, 7]

            if (item.length === 10 && parseInt(item, 10) > 0) {
                let b = 0

                for (let a = 0; a < 9; a++) {
                    b += parseInt(item.charAt(a)) * numbers[a]
                }

                return b % 11 === parseInt(item.charAt(9))
            }

            return false
        },
    },
    {
        name: 'regon',
        error: 'Błędny REGON',
        validator: (item: string): boolean => {
            var reg = /^[0-9]{9}$/;
            if(!reg.test(item))
                return false;
            else
            {
                var digits = (""+item).split("");
                var checksum = (8*parseInt(digits[0]) + 9*parseInt(digits[1]) + 2*parseInt(digits[2]) + 3*parseInt(digits[3]) + 4*parseInt(digits[4]) + 5*parseInt(digits[5]) + 6*parseInt(digits[6]) + 7*parseInt(digits[7]))%11;
                if(checksum == 10)
                    checksum = 0;

                return (parseInt(digits[8])==checksum);
            }
        },
    },
    {
        name: 'do', // ? Dowód Osobisty
        error: 'Niepoprawny numer dowodu osobistego',
        validator: (item: string): boolean => {
            // Check length
            if (item == null || item.length !== 9) {
                return false
            }

            item = item.toUpperCase()
            const letterValues = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

            // eslint-disable-next-line space-before-function-paren
            function getLetterValue(letter: string) {
                return letterValues.indexOf(letter)
            }

            // Check seria
            for (let i = 0; i < 3; i++) {
                if (getLetterValue(item[i]) < 10 || item[i] === 'O' || item === 'Q') {
                    return false
                }
            }

            // Check numbers
            for (let i = 3; i < 9; i++) {
                if (getLetterValue(item[i]) < 0 || getLetterValue(item[i]) > 9) {
                    return false
                }
            }

            // sprawdz cyfre kontrolna
            let sum =
                7 * getLetterValue(item[0]) +
                3 * getLetterValue(item[1]) +
                1 * getLetterValue(item[2]) +
                7 * getLetterValue(item[4]) +
                3 * getLetterValue(item[5]) +
                1 * getLetterValue(item[6]) +
                7 * getLetterValue(item[7]) +
                3 * getLetterValue(item[8])
            sum %= 10
            if (sum !== getLetterValue(item[3])) {
                return false
            }

            return true
        },
    },
    {
        name: 'postCode',
        error: 'Niepoprawny kod pocztowy',
        validator: (item: string): boolean => {
            return /^[0-9]{2}-[0-9]{3}$/.test(item)
        },
    },
    {
        name: 'otpPass',
        error: 'Niepoprawne hasło SMS',
        validator: (value: string): boolean => {
            return /[0-9]{4}/.test(value) && value.length === 4
        },
    },
    {
        name: 'only-numbers',
        error: 'Litery i specjalne znaki nie są dozwolone',
        validator: (value: string): boolean => {
            return /^[0-9]+$/.test(value)
        },
    },
    {
        name: 'only-letters',
        error: 'Cyfry i specjalne znaki nie są dozwolone',
        validator: (value: string): boolean => {
            return /^[A-Za-z]+$/.test(value)
        },
    },
    {
        name: 'name',
        error: 'Cyfry i specjalne znaki nie są dozwolone',
        validator: (value: string): boolean => {
            return /^[a-zA-ZàáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð ,.'-]+$/u.test(value)
        },
    },
]

function validate(value: FormValue, validation: string): boolean {
    const validationTypes = validation && validation.length > 0
        ? validation.split(' ')
        : []

    const test = validationTypes.map((type: String) => {
        const validatorObj = Validators.find((obj) => obj.name === type)
        return value && validatorObj ? validatorObj.validator(value.toString()) : false
    })

    return !test.some((result: boolean) => result === false)
}

function getValidationTypes(itemValidation: string = '') {
    return itemValidation ? itemValidation.split(' ').reverse() : []
}

function getErrorMsg(validation: string | undefined): string | null {
    if(!validation || validation.length === 0) return null;

    const validationArr = getValidationTypes(validation)
    let msg:string = ''

    validationArr.forEach(type => {
        const validatorObj = Validators.find(validator => validator.name === type)
        msg += validatorObj ? validatorObj.error : ''
        msg += type !== validationArr[validationArr.length - 1] ? ', ' : ''
    })

    return msg
}

function checkAllInputsAreValid(inputs: FormInput[]): boolean {
    let allValid = false
    if(inputs && inputs.length > 0){
        allValid = inputs.map((input) => {
            return typeof input.error !== 'undefined' && !['', null].includes(input.error) ||
                ['', null].includes((input.value as string)) && input.validation && input.validation.includes('required')
        }).filter(Boolean).length === 0
    }
    return allValid
}

export {validate, getErrorMsg, getValidationTypes, checkAllInputsAreValid}
export default Validators
