/**
 * We are defining all the global rules here and configuring
 * all the `vee-validate` settings.
 */
import { configure, defineRule, Field, Form, ErrorMessage } from "vee-validate";
import { localize, setLocale } from "@vee-validate/i18n";
import ar from "@vee-validate/i18n/dist/locale/ar.json";
import bn from "@vee-validate/i18n/dist/locale/bn.json";
import ca from "@vee-validate/i18n/dist/locale/ca.json";
import de from "@vee-validate/i18n/dist/locale/de.json";
import en from "@vee-validate/i18n/dist/locale/en.json";
import es from "@vee-validate/i18n/dist/locale/es.json";
import fa from "@vee-validate/i18n/dist/locale/fa.json";
import fr from "@vee-validate/i18n/dist/locale/fr.json";
import he from "@vee-validate/i18n/dist/locale/he.json";
import hi_IN from "../../locales/hi_IN.json";
import id from "@vee-validate/i18n/dist/locale/id.json";
import it from "@vee-validate/i18n/dist/locale/it.json";
import ja from "@vee-validate/i18n/dist/locale/ja.json";
import nl from "@vee-validate/i18n/dist/locale/nl.json";
import pl from "@vee-validate/i18n/dist/locale/pl.json";
import pt_BR from "@vee-validate/i18n/dist/locale/pt_BR.json";
import ru from "@vee-validate/i18n/dist/locale/ru.json";
import sin from "../../locales/sin.json";
import tr from "@vee-validate/i18n/dist/locale/tr.json";
import uk from "@vee-validate/i18n/dist/locale/uk.json";
import zh_CN from "@vee-validate/i18n/dist/locale/zh_CN.json";
import { all } from "@vee-validate/rules";

window.defineRule = defineRule;

export default {
    install: (app) => {
        /**
         * Global components registration;
         */
        app.component("VForm", Form);
        app.component("VField", Field);
        app.component("VErrorMessage", ErrorMessage);

        window.addEventListener("load", () => setLocale(document.documentElement.attributes.lang.value));

        /**
         * Registration of all global validators.
         */
        Object.entries(all).forEach(([name, rule]) => defineRule(name, rule));

        /**
         * This regular expression allows phone numbers with the following conditions:
         * - The phone number can start with an optional "+" sign.
         * - After the "+" sign, there should be one or more digits.
         *
         * This validation is sufficient for global-level phone number validation. If
         * someone wants to customize it, they can override this rule.
         */
        defineRule("phone", (value) => {
            if (!value || !value.length) {
                return true;
            }

            if (!/^\+?\d+$/.test(value)) {
                return false;
            }

            return true;
        });

        defineRule("address", (value) => {
            if (!value || !value.length) {
                return true;
            }

            if (
                !/^[a-zA-Z0-9\s.\/*'\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\u0590-\u05FF\u3040-\u309F\u30A0-\u30FF\u0400-\u04FF\u0D80-\u0DFF\u3400-\u4DBF\u2000-\u2A6D\u00C0-\u017F\u0980-\u09FF\u0900-\u097F\u4E00-\u9FFF,\(\)-]{1,60}$/iu.test(
                    value
                )
            ) {
                return false;
            }

            return true;
        });

        defineRule("postcode", (value) => {
            if (! value || ! value.length) {
                return true;
            }

            if (! /^[a-zA-Z0-9][a-zA-Z0-9\s-]*[a-zA-Z0-9]$/.test(value)) {
                return false;
            }

            return true;
        });

        defineRule(
            "decimal",
            (value, { decimals = "*", separator = "." } = {}) => {
                if (value === null || value === undefined || value === "") {
                    return true;
                }

                if (Number(decimals) === 0) {
                    return /^-?\d*$/.test(value);
                }

                const regexPart = decimals === "*" ? "+" : `{1,${decimals}}`;
                const regex = new RegExp(
                    `^[-+]?\\d*(\\${separator}\\d${regexPart})?([eE]{1}[-]?\\d+)?$`
                );

                return regex.test(value);
            }
        );

        configure({
            /**
             * Built-in error messages and custom error messages are available. Multiple
             * locales can be added in the same way.
             */
            generateMessage: localize({
                en: {
                    ...en,
                    messages: {
                        ...en.messages,
                        phone: "This {field} must be a valid phone number",
                        address: "This {field} must be a valid address",
                    },
                },

                ar: {
                    ...ar,
                    messages: {
                        ...ar.messages,
                        phone: "يجب أن يكون هذا {field} رقم هاتف صالح",
                        address: "يجب أن يكون هذا {field} عنوانًا صالحًا",
                    },
                },

                bn: {
                    ...bn,
                    messages: {
                        ...bn.messages,
                        phone: "এই {field} একটি বৈধ ফোন নম্বর হতে হবে",
                        address: "এই {field} একটি বৈধ ঠিকানা হতে হবে",
                    },
                },

                ca: {
                    ...ca,
                    messages: {
                        ...ca.messages,
                        phone: "Aquest {field} ha de ser un número de telèfon vàlid",
                        address: "Aquest {field} ha de ser una adreça vàlida",
                    },
                },

                de: {
                    ...de,
                    messages: {
                        ...de.messages,
                        phone: "Dieses {field} muss eine gültige Telefonnummer sein",
                        address: "Diese {field} muss eine gültige Adresse sein",
                    },
                },

                es: {
                    ...es,
                    messages: {
                        ...es.messages,
                        phone: "Este {field} debe ser un número de teléfono válido",
                        address: "Esta {field} debe ser una dirección válida",
                    },
                },

                fa: {
                    ...fa,
                    messages: {
                        ...fa.messages,
                        phone: "این {field} باید یک شماره تلفن معتبر باشد",
                        address: "این {field} باید یک آدرس معتبر باشد",
                    },
                },

                fr: {
                    ...fr,
                    messages: {
                        ...fr.messages,
                        phone: "Ce {field} doit être un numéro de téléphone valide",
                        address: "Cette {field} doit être une adresse valide",
                    },
                },

                he: {
                    ...he,
                    messages: {
                        ...he.messages,
                        phone: "זה {field} חייב להיות מספר טלפון תקין",
                        address: "זה {field} חייב להיות כתובת תקינה",
                    },
                },

                hi_IN: {
                    ...hi_IN,
                    messages: {
                        ...hi_IN.messages,
                        phone: "यह {field} कोई मान्य फ़ोन नंबर होना चाहिए",
                        address: "यह {field} एक मान्य पता होना चाहिए",
                    },
                },

                id: {
                    ...id,
                    messages: {
                        ...id.messages,
                        phone: "Nomor telepon {field} harus valid",
                        address: "Alamat {field} harus valid",
                    },
                },

                it: {
                    ...it,
                    messages: {
                        ...it.messages,
                        phone: "Questo {field} deve essere un numero di telefono valido",
                        address: "Questo {field} deve essere un indirizzo valido",
                    },
                },

                ja: {
                    ...ja,
                    messages: {
                        ...ja.messages,
                        phone: "この{field}は有効な電話番号である必要があります",
                        address: "この{field}は有効な住所である必要があります",
                    },
                },

                nl: {
                    ...nl,
                    messages: {
                        ...nl.messages,
                        phone: "Dit {field} moet een geldig telefoonnummer zijn",
                        address: "Dit {field} moet een geldig adres zijn",
                    },
                },

                pl: {
                    ...pl,
                    messages: {
                        ...pl.messages,
                        phone: "Pole {field} musi zawierać prawidłowy numer telefonu",
                        address: "Pole {field} musi zawierać prawidłowy adres",
                    },
                },

                pt_BR: {
                    ...pt_BR,
                    messages: {
                        ...pt_BR.messages,
                        phone: "Este {field} deve ser um número de telefone válido",
                        address: "Este {field} deve ser um endereço válido",
                    },
                },

                ru: {
                    ...ru,
                    messages: {
                        ...ru.messages,
                        phone: "Это {field} должно быть действительным номером телефона",
                        address: "Это {field} должно быть действительным адресом",
                    },
                },

                sin: {
                    ...sin,
                    messages: {
                        ...sin.messages,
                        phone: "මෙම {field} වටේ වලංගු දුරකතන අංකය විය යුතුයි",
                        address: "මෙම {field} වටේ වලංගු ලිපිනය විය යුතුයි",
                    },
                },

                tr: {
                    ...tr,
                    messages: {
                        ...tr.messages,
                        phone: "Bu {field} geçerli bir telefon numarası olmalıdır",
                        address: "Bu {field} geçerli bir adres olmalıdır",
                    },
                },

                uk: {
                    ...uk,
                    messages: {
                        ...uk.messages,
                        phone: "Це {field} повинно бути дійсним номером телефону",
                        address: "Це {field} повинно бути дійсною адресою",
                    },
                },

                zh_CN: {
                    ...zh_CN,
                    messages: {
                        ...zh_CN.messages,
                        phone: "这个 {field} 必须是一个有效的电话号码",
                        address: "这个 {field} 必须是一个有效的地址",
                    },
                },
            }),

            validateOnBlur: true,
            validateOnInput: true,
            validateOnChange: true,
        });
    },
};
