<template>
    <div v-if="!$connection">Failed to connect to conditions.</div>

    <input v-else-if="attributes.disabled" disabled class="uk-input" :value="input" />

    <div v-else>
        <input
            v-model.trim="input"
            :list="id"
            v-bind="attributes"
            class="uk-input"
            type="text"
            :placeholder="createQuery('AND')"
            :class="{
                'uk-text-danger': error,
            }"
        />

        <div v-if="error" class="uk-text-danger uk-text-small">{{ error }}</div>

        <datalist :id="id">
            <option v-if="conditions.length === 2" :value="createQuery('AND')">AND</option>
            <option v-if="conditions.length === 2" :value="createQuery('OR')">OR</option>
            <option v-if="conditions.length > 2" :value="createGroupedQuery('AND')">AND</option>
            <option v-if="conditions.length > 2" :value="createGroupedQuery('OR')">OR</option>
        </datalist>
    </div>
</template>

<script>
import fields from '@yootheme/fields';

const errors = {
    'unknown-condition': 'Unknown condition stated',
    'missing-condition': 'Not all conditions stated',
    'invalid-syntax': 'Invalid Syntax',
};

export default {
    extends: fields.components.FieldText,

    data: () => ({
        draft: '',
    }),

    computed: {
        input: {
            set(val) {
                this.draft = val;

                if (!this.error) {
                    this.value = val;
                }
            },

            get() {
                return this.draft;
            },
        },

        validation() {
            return this.validate(this.draft);
        },

        error() {
            if (this.validation !== true) {
                return errors[this.validation];
            }

            return '';
        },

        id() {
            return `simple-query-field-${this.name}`;
        },

        $connection() {
            return this.values?.[this.field?.connection];
        },

        conditions() {
            return (this.$connection || []).map((c, i) => (i + 1).toString());
        },

        totalConditions() {
            return this.conditions.length;
        },

        defaultQuery() {
            return this.conditions.map((q) => `(${q})`).join(' AND ');
        },
    },

    created() {
        this.draft = this.value;
    },

    methods: {
        createQuery(operator = 'AND') {
            return this.conditions.map((q) => `{${q}}`).join(` ${operator} `);
        },

        createGroupedQuery(operator = 'AND') {
            const inverse = operator === 'AND' ? 'OR' : 'AND';

            const query = this.createQuery(inverse).replace(/(\{\d\} (OR|AND) \{\d\})/g, '($1)');

            if (operator === 'AND') {
                return query.replace(/\) (OR) (\{|\()/g, ') AND $2');
            } else {
                return query.replace(/\) (AND) (\{|\()/g, ') OR $2');
            }
        },

        validate(value) {
            if (!value) {
                return true;
            }

            const operatorRegex = /[})]([^{}()]*)[{(]/g;
            const conditionRegex = /\{([\w ]*)\}/g;

            const openingParenthesis = value.match(/\(/g);
            const closingParenthesis = value.match(/\)/g);
            const openingBrackets = value.match(/\{/g);
            const closingBrackets = value.match(/\}/g);
            const operators = Array.from(value.matchAll(operatorRegex))
                .map((g) => g[1])
                .filter(Boolean);
            const conditions = Array.from(value.matchAll(conditionRegex))
                .map((g) => g[1])
                .filter(Boolean);

            if (value.match(/[^0-9{}()ANDOR ]/)) {
                return 'invalid-syntax';
            }

            if (value.match(/(^[^{(])|[^})]$/)) {
                return 'invalid-syntax';
            }

            if (value.match(/{}|\(\)/)) {
                return 'invalid-syntax';
            }

            if (openingParenthesis?.length !== closingParenthesis?.length) {
                return 'invalid-syntax';
            }

            if (openingBrackets?.length !== closingBrackets?.length) {
                return 'invalid-syntax';
            }

            if (!operators.every((o) => o.trim().match(/^(AND|OR)$/))) {
                return 'invalid-syntax';
            }

            if (!conditions.every((name) => this.conditions.includes(name))) {
                return 'unknown-condition';
            }

            // if (!this.conditions.every(name => conditions.includes(name))) {
            //     return 'missing-condition';
            // }

            return true;
        },
    },
};
</script>
