import $ from "jquery";
import { flow, observable, runInAction, set } from "mobx";
import wp from "wp";

import { request } from "../utils/request.js";
import { locationRestHandlerDelete } from "../wp-api/handler.delete.js";
import { locationRestHandlerPost } from "../wp-api/handler.post.js";

import type { QueueStore } from "../store/queue.js";
import type { ClassProperties } from "../utils/types.js";
import type {
    ParamsRestHandlerDelete,
    RequestRestHandlerDelete,
    ResponseRestHandlerDelete,
} from "../wp-api/handler.delete.js";
import type { ParamsRestHandlerPost, RequestRestHandlerPost, ResponseRestHandlerPost } from "../wp-api/handler.post.js";

type CancellablePromise<R> = ReturnType<ReturnType<typeof flow<R, any>>>;

class Handler {
    @observable
    public id: string;

    @observable
    public file: string;

    @observable
    public name: string;

    @observable
    public error: string;

    @observable
    public author: string;

    @observable
    public origin: string;

    @observable
    public installUrl?: string;

    @observable
    public isActivated: boolean;

    @observable
    public isInstalled: boolean;

    @observable
    public isHandler: boolean;

    @observable
    public activatePluginUrl: string;

    @observable
    public busy = false;

    public readonly queueStore: QueueStore;

    public constructor(handler: ClassProperties<Handler>, queueStore: QueueStore) {
        this.queueStore = queueStore;
        runInAction(() => set(this, handler));
    }

    public toggle: () => CancellablePromise<void> = flow(function* (this: Handler) {
        this.busy = true;
        try {
            if (this.isHandler) {
                yield request<RequestRestHandlerDelete, ParamsRestHandlerDelete, ResponseRestHandlerDelete>({
                    location: locationRestHandlerDelete,
                    request: {
                        handler: this.id,
                    },
                });
            } else {
                yield request<RequestRestHandlerPost, ParamsRestHandlerPost, ResponseRestHandlerPost>({
                    location: locationRestHandlerPost,
                    request: {
                        handler: this.id,
                    },
                });
            }

            // Deactivate others and activate me
            !this.isHandler && this.queueStore.handlers.forEach((o) => o.isHandler && (o.isHandler = false));
            this.isHandler = !this.isHandler;
        } finally {
            this.busy = false;
        }
    });

    public installAndActivate: () => CancellablePromise<void> = flow(function* (this: Handler) {
        this.busy = true;
        const ajaxSend: (options: any) => Promise<void> = wp?.ajax?.send; // wp-utils.js is not loaded on frontend, so it is optional

        // Try to install plugin via AJAX request
        if (this.isInstalled) {
            // Immediate activate the plugin
            try {
                yield $.get(this.activatePluginUrl).promise();
                this.isActivated = true;

                // Immediate activate the plugin as rename handler
                yield this.toggle();
            } catch (e) {
                // Fallback to usual redirect
                window.location.href = this.activatePluginUrl;
            }
        } else {
            if (ajaxSend) {
                try {
                    yield ajaxSend({
                        data: {
                            action: "install-plugin",
                            slug: this.id,
                            _ajax_nonce: this.queueStore.rootStore.optionStore.others.installPluginNonce,
                        },
                    });

                    this.isInstalled = true;

                    yield this.installAndActivate();
                } catch (e) {
                    // Fallback to install url (this can happen if FTP is configured to install plugin)
                    window.location.href = this.installUrl;
                }
            } else {
                window.location.href = this.installUrl;
            }
        }
    });
}

export { Handler };
