import { computed, flow, observable } from "mobx";

import { BaseOptions } from "@devowl-wp/utils";

import { request } from "../utils/request.js";
import { locationRestChecklistGet } from "../wp-api/checklist.get.js";
import { locationRestChecklistPut } from "../wp-api/checklist.put.js";

import type { RootStore } from "./stores.js";
import type {
    ParamsRouteChecklistGet,
    RequestRouteChecklistGet,
    ResponseRouteChecklistGet,
} from "../wp-api/checklist.get.js";
import type {
    ParamsRouteChecklistPut,
    RequestRouteChecklistPut,
    ResponseRouteChecklistPut,
} from "../wp-api/checklist.put.js";

class ChecklistStore extends BaseOptions {
    @observable
    public busyChecklist = false;

    @observable
    public checklist: ResponseRouteChecklistGet;

    public readonly rootStore: RootStore;

    public constructor(rootStore: RootStore) {
        super();
        this.rootStore = rootStore;
    }

    @computed
    public get items() {
        return (
            (this.checklist && Object.keys(this.checklist.items).map((id) => ({ id, ...this.checklist.items[id] }))) ||
            []
        );
    }

    @computed
    public get completed() {
        return this.items.filter(({ checked }) => checked);
    }

    @computed
    public get checkable() {
        const { isPro } = this.rootStore.optionStore.others;
        return this.items.filter(({ needsPro }) => !needsPro || (isPro && needsPro));
    }

    @computed
    public get done() {
        return this.completed.length >= this.checkable.length || !!this.checklist?.dismissed;
    }

    public probablyFetchByChangedItem: (itemId: string | string[], force?: boolean) => Promise<void> = flow(function* (
        this: ChecklistStore,
        itemId,
        force,
    ) {
        if (force) {
            yield this.fetchChecklist();
            return;
        }

        const useItemIds = !Array.isArray(itemId) ? [itemId] : itemId;
        if (this.items.filter(({ id, checked }) => useItemIds.indexOf(id) > -1 && !checked).length > 0) {
            yield this.fetchChecklist();
        }
    });

    public fetchChecklist: () => Promise<void> = flow(function* (this: ChecklistStore) {
        this.busyChecklist = true;
        try {
            this.checklist = yield request<
                RequestRouteChecklistGet,
                ParamsRouteChecklistGet,
                ResponseRouteChecklistGet
            >({
                location: locationRestChecklistGet,
                sendReferer: true,
            });
        } catch (e) {
            console.log(e);
            throw e;
        } finally {
            this.busyChecklist = false;
        }
    });

    public toggleChecklistItem: (id: string, state: boolean) => Promise<void> = flow(function* (
        this: ChecklistStore,
        id,
        state,
    ) {
        this.busyChecklist = true;
        try {
            this.checklist = yield request<
                RequestRouteChecklistPut,
                ParamsRouteChecklistPut,
                ResponseRouteChecklistPut
            >({
                location: locationRestChecklistPut,
                request: {
                    state,
                },
                sendReferer: true,
                params: {
                    id,
                },
            });
        } catch (e) {
            console.log(e);
            throw e;
        } finally {
            this.busyChecklist = false;
        }
    });
}

export { ChecklistStore };
