<template>
    <a
        class="btn"
        :class="getClassButton"
        :title="$t(buttonTitle || '')"
        @click="openModal"
    >
        <span v-if="displayTextButton">{{ $t(buttonTitle || "") }}</span>
    </a>

    <teleport to="body">
        <modal
            v-if="modal.showModal"
            :modal-dialog-class="modal.modalDialogClass"
            @close="modal.showModal = false"
        >
            <template #header>
                <h3 class="modal-title">
                    {{ $t(modalTitle) }}
                </h3>
            </template>

            <template #body-head>
                <div class="modal-body">
                    <div class="search">
                        <label class="col-form-label" style="float: right">
                            {{
                                $tc(
                                    "add_persons.suggested_counter",
                                    suggestedCounter,
                                )
                            }}
                        </label>

                        <input
                            id="search-persons"
                            name="query"
                            v-model="query"
                            :placeholder="$t('add_persons.search_some_persons')"
                            ref="search"
                        />
                        <i class="fa fa-search fa-lg" />
                        <i
                            class="fa fa-times"
                            v-if="queryLength >= 3"
                            @click="resetSuggestion"
                        />
                    </div>
                </div>
                <div class="modal-body" v-if="checkUniq === 'checkbox'">
                    <div class="count">
                        <span>
                            <a v-if="suggestedCounter > 2" @click="selectAll">
                                {{ $t("action.check_all") }}
                            </a>
                            <a
                                v-if="selectedCounter > 0"
                                @click="resetSelection"
                            >
                                <i v-if="suggestedCounter > 2"> • </i>
                                {{ $t("action.reset") }}
                            </a>
                        </span>
                        <span v-if="selectedCounter > 0">
                            {{
                                $tc(
                                    "add_persons.selected_counter",
                                    selectedCounter,
                                )
                            }}
                        </span>
                    </div>
                </div>
            </template>

            <template #body>
                <div class="results">
                    <person-suggestion
                        v-for="item in this.selectedAndSuggested
                            .slice()
                            .reverse()"
                        :key="itemKey(item)"
                        :item="item"
                        :search="search"
                        :type="checkUniq"
                        @save-form-on-the-fly="saveFormOnTheFly"
                        @new-prior-suggestion="newPriorSuggestion"
                        @update-selected="updateSelected"
                    />

                    <div class="create-button">
                        <on-the-fly
                            v-if="
                                queryLength >= 3 &&
                                (options.type.includes('person') ||
                                    options.type.includes('thirdparty'))
                            "
                            :button-text="
                                $t('onthefly.create.button', { q: query })
                            "
                            :allowed-types="options.type"
                            :query="query"
                            action="create"
                            @save-form-on-the-fly="saveFormOnTheFly"
                            ref="onTheFly"
                        />
                    </div>
                </div>
            </template>

            <template #footer>
                <button
                    class="btn btn-create"
                    @click.prevent="$emit('addNewPersons', { selected, modal })"
                >
                    {{ $t("action.add") }}
                </button>
            </template>
        </modal>
    </teleport>
</template>

<script>
import Modal from "ChillMainAssets/vuejs/_components/Modal";
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
import PersonSuggestion from "./AddPersons/PersonSuggestion";
import { searchEntities } from "ChillPersonAssets/vuejs/_api/AddPersons";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";

export default {
    name: "AddPersons",
    components: {
        Modal,
        PersonSuggestion,
        OnTheFly,
    },
    props: ["buttonTitle", "modalTitle", "options"],
    emits: ["addNewPersons"],
    data() {
        return {
            modal: {
                showModal: false,
                modalDialogClass: "modal-dialog-scrollable modal-xl",
            },
            search: {
                query: "",
                previousQuery: "",
                currentSearchQueryController: null,
                suggested: [],
                selected: [],
                priorSuggestion: {},
            },
        };
    },
    computed: {
        query: {
            set(query) {
                return this.setQuery(query);
            },
            get() {
                return this.search.query;
            },
        },
        queryLength() {
            return this.search.query.length;
        },
        suggested() {
            return this.search.suggested;
        },
        suggestedCounter() {
            return this.search.suggested.length;
        },
        selected() {
            return this.search.selected;
        },
        selectedCounter() {
            return this.search.selected.length;
        },
        selectedAndSuggested() {
            this.addPriorSuggestion();
            const uniqBy = (a, key) => [
                ...new Map(a.map((x) => [key(x), x])).values(),
            ];
            let union = [
                ...new Set([
                    ...this.suggested.slice().reverse(),
                    ...this.selected.slice().reverse(),
                ]),
            ];
            return uniqBy(union, (k) => k.key);
        },
        getClassButton() {
            let size =
                typeof this.options.button !== "undefined" &&
                typeof this.options.button.size !== "undefined"
                    ? this.options.button.size
                    : "";
            let type =
                typeof this.options.button !== "undefined" &&
                typeof this.options.button.type !== "undefined"
                    ? this.options.button.type
                    : "btn-create";
            return size ? size + " " + type : type;
        },
        displayTextButton() {
            return typeof this.options.button !== "undefined" &&
                typeof this.options.button.display !== "undefined"
                ? this.options.button.display
                : true;
        },
        checkUniq() {
            if (this.options.uniq === true) {
                return "radio";
            }
            return "checkbox";
        },
        priorSuggestion() {
            return this.search.priorSuggestion;
        },
        hasPriorSuggestion() {
            return this.search.priorSuggestion.key ? true : false;
        },
    },
    methods: {
        openModal() {
            this.modal.showModal = true;
            this.$nextTick(function () {
                this.$refs.search.focus();
            });
        },
        setQuery(query) {
            this.search.query = query;

            setTimeout(
                function () {
                    if (query === "") {
                        this.loadSuggestions([]);
                        return;
                    }
                    if (query === this.search.query) {
                        if (this.search.currentSearchQueryController !== null) {
                            this.search.currentSearchQueryController.abort();
                        }
                        this.search.currentSearchQueryController =
                            new AbortController();
                        searchEntities(
                            { query, options: this.options },
                            this.search.currentSearchQueryController.signal,
                        )
                            .then(
                                (suggested) =>
                                    new Promise((resolve) => {
                                        this.loadSuggestions(suggested.results);
                                        resolve();
                                    }),
                            )
                            .catch((error) => {
                                if (error instanceof DOMException) {
                                    if (error.name === "AbortError") {
                                        console.log(
                                            "request aborted due to user continue typing",
                                        );
                                        return;
                                    }
                                }

                                throw error;
                            });
                    }
                }.bind(this),
                query.length > 3 ? 300 : 700,
            );
        },
        loadSuggestions(suggested) {
            this.search.suggested = suggested;
            this.search.suggested.forEach(function (item) {
                item.key = this.itemKey(item);
            }, this);
        },
        updateSelected(value) {
            //console.log('value', value);
            this.search.selected = value;
        },
        resetSearch() {
            this.resetSelection();
            this.resetSuggestion();
        },
        resetSuggestion() {
            this.search.query = "";
            this.search.suggested = [];
        },
        resetSelection() {
            this.search.selected = [];
        },
        selectAll() {
            this.search.suggested.forEach(function (item) {
                this.search.selected.push(item);
            }, this);
        },
        itemKey(item) {
            return item.result.type + item.result.id;
        },
        addPriorSuggestion() {
            // console.log('prior suggestion', this.priorSuggestion);
            if (this.hasPriorSuggestion) {
                // console.log('addPriorSuggestion',);
                this.suggested.unshift(this.priorSuggestion);
                this.selected.unshift(this.priorSuggestion);

                this.newPriorSuggestion(null);
            }
        },
        newPriorSuggestion(entity) {
            // console.log('newPriorSuggestion', entity);
            if (entity !== null) {
                let suggestion = {
                    key: entity.type + entity.id,
                    relevance: 0.5,
                    result: entity,
                };
                this.search.priorSuggestion = suggestion;
                // console.log('search priorSuggestion', this.search.priorSuggestion);
                this.addPriorSuggestion(suggestion);
            } else {
                this.search.priorSuggestion = {};
            }
        },
        saveFormOnTheFly({ type, data }) {
            console.log(
                "saveFormOnTheFly from addPersons, type",
                type,
                ", data",
                data,
            );
            if (type === "person") {
                makeFetch("POST", "/api/1.0/person/person.json", data)
                    .then((responsePerson) => {
                        this.newPriorSuggestion(responsePerson);
                        this.$refs.onTheFly.closeModal();

                        if (null !== data.addressId) {
                            const household = {
                                type: "household",
                            };
                            const address = {
                                id: data.addressId,
                            };
                            makeFetch(
                                "POST",
                                "/api/1.0/person/household.json",
                                household,
                            )
                                .then((responseHousehold) => {
                                    const member = {
                                        concerned: [
                                            {
                                                person: {
                                                    type: "person",
                                                    id: responsePerson.id,
                                                },
                                                start_date: {
                                                    // TODO: use date.ts methods (low priority)
                                                    datetime: `${new Date().toISOString().split("T")[0]}T00:00:00+02:00`,
                                                },
                                                holder: false,
                                                comment: null,
                                            },
                                        ],
                                        destination: {
                                            type: "household",
                                            id: responseHousehold.id,
                                        },
                                        composition: null,
                                    };
                                    return makeFetch(
                                        "POST",
                                        "/api/1.0/person/household/members/move.json",
                                        member,
                                    )
                                        .then(() => {
                                            makeFetch(
                                                "POST",
                                                `/api/1.0/person/household/${responseHousehold.id}/address.json`,
                                                address,
                                            )
                                                .then((_response) => {
                                                    console.log(_response);
                                                })
                                                .catch((error) => {
                                                    if (
                                                        error.name ===
                                                        "ValidationException"
                                                    ) {
                                                        for (let v of error.violations) {
                                                            this.$toast.open({
                                                                message: v,
                                                            });
                                                        }
                                                    } else {
                                                        this.$toast.open({
                                                            message:
                                                                "An error occurred",
                                                        });
                                                    }
                                                });
                                        })
                                        .catch((error) => {
                                            if (
                                                error.name ===
                                                "ValidationException"
                                            ) {
                                                for (let v of error.violations) {
                                                    this.$toast.open({
                                                        message: v,
                                                    });
                                                }
                                            } else {
                                                this.$toast.open({
                                                    message:
                                                        "An error occurred",
                                                });
                                            }
                                        });
                                })
                                .catch((error) => {
                                    if (error.name === "ValidationException") {
                                        for (let v of error.violations) {
                                            this.$toast.open({ message: v });
                                        }
                                    } else {
                                        this.$toast.open({
                                            message: "An error occurred",
                                        });
                                    }
                                });
                        }
                    })
                    .catch((error) => {
                        if (error.name === "ValidationException") {
                            for (let v of error.violations) {
                                this.$toast.open({ message: v });
                            }
                        } else {
                            this.$toast.open({ message: "An error occurred" });
                        }
                    });
            } else if (type === "thirdparty") {
                makeFetch("POST", "/api/1.0/thirdparty/thirdparty.json", data)
                    .then((response) => {
                        this.newPriorSuggestion(response);
                        this.$refs.onTheFly.closeModal();
                    })
                    .catch((error) => {
                        if (error.name === "ValidationException") {
                            for (let v of error.violations) {
                                this.$toast.open({ message: v });
                            }
                        } else {
                            this.$toast.open({ message: "An error occurred" });
                        }
                    });
            }
        },
    },
};
</script>

<style lang="scss">
li.add-persons {
    a {
        cursor: pointer;
    }
}
div.body-head {
    overflow-y: unset;
    div.modal-body:first-child {
        margin: auto 4em;
        div.search {
            position: relative;
            input {
                width: 100%;
                padding: 1.2em 1.5em 1.2em 2.5em;
                //margin: 1em 0;
            }
            i {
                position: absolute;
                opacity: 0.5;
                padding: 0.65em 0;
                top: 50%;
            }
            i.fa-search {
                left: 0.5em;
            }
            i.fa-times {
                right: 1em;
                padding: 0.75em 0;
                cursor: pointer;
            }
        }
    }
    div.modal-body:last-child {
        padding-bottom: 0;
    }
    div.count {
        margin: -0.5em 0 0.7em;
        display: flex;
        justify-content: space-between;
        a {
            cursor: pointer;
        }
    }
}
.create-button > a {
    margin-top: 0.5em;
    margin-left: 2.6em;
}
</style>
