/* eslint-disable camelcase */
import Component from '@glimmer/component';
import RSVP from 'rsvp';
import {action} from '@ember/object';
import {isBlank, isEmpty} from '@ember/utils';
import {pluralize} from 'ember-inflector';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
import {task, timeout, waitForProperty} from 'ember-concurrency';

export default class GhSearchInputComponent extends Component {
    @service ajax;
    @service notifications;
    @service router;
    @service store;

    content = [];
    contentExpiresAt = false;
    contentExpiry = 30000;

    searchables = [{
        name: 'Posts',
        model: 'post',
        fields: ['id', 'title'],
        idField: 'id',
        titleField: 'title'
    }, {
        name: 'Pages',
        model: 'page',
        fields: ['id', 'title'],
        idField: 'id',
        titleField: 'title'
    }, {
        name: 'Users',
        model: 'user',
        fields: ['slug', 'name'],
        idField: 'slug',
        titleField: 'name'
    }, {
        name: 'Tags',
        model: 'tag',
        fields: ['slug', 'name'],
        idField: 'slug',
        titleField: 'name'
    }];

    @action
    openSelected(selected) {
        if (!selected) {
            return;
        }

        this.args.onSelected?.(selected);

        if (selected.searchable === 'Posts') {
            let id = selected.id.replace('post.', '');
            this.router.transitionTo('lexical-editor.edit', 'post', id);
        }

        if (selected.searchable === 'Pages') {
            let id = selected.id.replace('page.', '');
            this.router.transitionTo('lexical-editor.edit', 'page', id);
        }

        if (selected.searchable === 'Users') {
            let id = selected.id.replace('user.', '');
            this.router.transitionTo('settings-x.settings-x', `staff/${id}`);
        }

        if (selected.searchable === 'Tags') {
            let id = selected.id.replace('tag.', '');
            this.router.transitionTo('tag', id);
        }
    }

    @action
    onClose(select, keyboardEvent) {
        // refocus search input after dropdown is closed (eg, by pressing Escape)
        run.later(() => {
            keyboardEvent?.target.focus();
        });
    }

    @task({restartable: true})
    *searchTask(term) {
        if (isBlank(term)) {
            return [];
        }

        // start loading immediately in the background
        this.refreshContentTask.perform();

        // debounce searches to 200ms to avoid thrashing CPU
        yield timeout(200);

        // wait for any on-going refresh to finish
        if (this.refreshContentTask.isRunning) {
            yield waitForProperty(this, 'refreshContentTask.isIdle');
        }

        const searchResult = this._searchContent(term);

        return searchResult;
    }

    _searchContent(term) {
        const normalizedTerm = term.toString().toLowerCase();
        const results = [];

        this.searchables.forEach((searchable) => {
            const matchedContent = this.content.filter((item) => {
                const normalizedTitle = item.title.toString().toLowerCase();
                return (item.searchable === searchable.name) && (normalizedTitle.indexOf(normalizedTerm) >= 0);
            });

            if (!isEmpty(matchedContent)) {
                results.push({
                    groupName: searchable.name,
                    options: matchedContent
                });
            }
        });

        return results;
    }

    @task({drop: true})
    *refreshContentTask() {
        let now = new Date();
        let contentExpiresAt = this.contentExpiresAt;

        if (contentExpiresAt > now) {
            return true;
        }

        const content = [];
        const promises = this.searchables.map(searchable => this._loadSearchable(searchable, content));

        try {
            yield RSVP.all(promises);
            this.content = content;
        } catch (error) {
            // eslint-disable-next-line
            console.error(error);
        }

        let contentExpiry = this.contentExpiry;
        this.contentExpiresAt = new Date(now.getTime() + contentExpiry);
    }

    _loadSearchable(searchable, content) {
        let url = `${this.store.adapterFor(searchable.model).urlForQuery({}, searchable.model)}/`;
        let maxSearchableLimit = '10000';
        let query = {fields: searchable.fields, limit: maxSearchableLimit};

        return this.ajax.request(url, {data: query}).then((response) => {
            const items = response[pluralize(searchable.model)].map(item => ({
                id: `${searchable.model}.${item[searchable.idField]}`,
                title: item[searchable.titleField],
                searchable: searchable.name
            }));

            content.push(...items);
        }).catch((error) => {
            this.notifications.showAPIError(error, {key: `search.load${searchable.name}.error`});
        });
    }
}
