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

import { License } from "./license.js";
import { request } from "../utils/request.js";
import { locationRestAnnouncementActive } from "../wp-api/announcementActive.post.js";
import { locationRestPluginUpdatePatch } from "../wp-api/pluginUpdate.patch.js";
import { locationRestPluginUpdateSkipPost } from "../wp-api/pluginUpdateSkip.post.js";

import type { PluginUpdateStore } from "../store/pluginUpdateStore.js";
import type {
    ParamsRouteAnnouncementActive,
    RequestRouteAnnouncementActive,
    ResponseRouteAnnouncementActive,
} from "../wp-api/announcementActive.post.js";
import type { ResponseRoutePluginUpdateGet } from "../wp-api/pluginUpdate.get.js";
import type {
    ParamsRoutePluginUpdatePatch,
    RequestRoutePluginUpdatePatch,
    ResponseRoutePluginUpdatePatch,
    ResponseRoutePluginUpdatePatchErrorInvalidKeysData,
} from "../wp-api/pluginUpdate.patch.js";
import type {
    ParamsRoutePluginUpdateSkipPost,
    RequestRoutePluginUpdateSkipPost,
    ResponseRoutePluginUpdateSkipPost,
} from "../wp-api/pluginUpdateSkip.post.js";

class PluginUpdate {
    @observable
    public busy = false;

    @observable
    public slug: ResponseRoutePluginUpdateGet["slug"];

    @observable
    public licenses: License[];

    @observable
    public hasInteractedWithFormOnce: ResponseRoutePluginUpdateGet["hasInteractedWithFormOnce"];

    @observable
    public name: ResponseRoutePluginUpdateGet["name"];

    @observable
    public needsLicenseKeys: ResponseRoutePluginUpdateGet["needsLicenseKeys"];

    @observable
    public announcementsActive: ResponseRoutePluginUpdateGet["announcementsActive"];

    @observable
    public allowsAutoUpdates: ResponseRoutePluginUpdateGet["allowsAutoUpdates"];

    @observable
    public allowsTelemetry: ResponseRoutePluginUpdateGet["allowsTelemetry"];

    @observable
    public allowsNewsletter: ResponseRoutePluginUpdateGet["allowsNewsletter"];

    @observable
    public potentialNewsletterUser: ResponseRoutePluginUpdateGet["potentialNewsletterUser"];

    @observable
    public privacyProvider: ResponseRoutePluginUpdateGet["privacyProvider"];

    @observable
    public privacyPolicy: ResponseRoutePluginUpdateGet["privacyPolicy"];

    @observable
    public accountSiteUrl: ResponseRoutePluginUpdateGet["accountSiteUrl"];

    @observable
    public additionalCheckboxes: ResponseRoutePluginUpdateGet["additionalCheckboxes"] = [];

    @observable
    public licenseKeyHelpUrl: ResponseRoutePluginUpdateGet["licenseKeyHelpUrl"];

    @observable
    public checkUpdateLink: ResponseRoutePluginUpdateGet["checkUpdateLink"];

    @observable
    public invalidKeysError: ResponseRoutePluginUpdatePatchErrorInvalidKeysData;

    @observable
    public showBlogName: ResponseRoutePluginUpdateGet["showBlogName"] = false;

    @observable
    public showNetworkWideUpdateIssueNotice: ResponseRoutePluginUpdateGet["showNetworkWideUpdateIssueNotice"] = false;

    public readonly store: PluginUpdateStore;

    @computed
    public get licensedEntries() {
        return this.licenses.filter(({ code }) => code);
    }

    @computed
    public get unlicensedEntries() {
        return this.licenses.filter(({ code }) => !code);
    }

    @computed
    public get noUsageEntries() {
        return this.unlicensedEntries.filter(({ noUsage }) => noUsage);
    }

    @computed
    public get modifiableEntries() {
        return this.unlicensedEntries.filter(({ programmatically }) => !programmatically);
    }

    @computed
    public get isLicensed() {
        return this.unlicensedEntries.length === 0;
    }

    public constructor(pluginUpdate: Partial<ResponseRoutePluginUpdateGet>, store: PluginUpdateStore) {
        this.fromResponse(pluginUpdate);
        this.store = store;
    }

    @action
    public fromResponse({ licenses, ...pluginUpdate }: Partial<ResponseRoutePluginUpdateGet>) {
        set(this, pluginUpdate);

        this.licenses = [];
        licenses?.forEach((license) => {
            this.licenses.push(new License(license, this));
        });
    }

    public setAnnouncementActive: (state: boolean) => Promise<boolean> = flow(function* (this: PluginUpdate, state) {
        this.busy = true;
        try {
            const result: ResponseRouteAnnouncementActive = yield request<
                RequestRouteAnnouncementActive,
                ParamsRouteAnnouncementActive,
                ResponseRouteAnnouncementActive
            >({
                location: locationRestAnnouncementActive,
                params: {
                    slug: this.slug,
                },
                request: {
                    state,
                },
            });

            if (result.success) {
                this.announcementsActive = state;
            }

            return result.success;
        } catch (e) {
            console.log(e);
            throw e;
        } finally {
            this.busy = false;
        }
    });

    public update: (data: RequestRoutePluginUpdatePatch) => Promise<void> = flow(function* (this: PluginUpdate, data) {
        this.busy = true;
        this.invalidKeysError = undefined;
        try {
            const result: ResponseRoutePluginUpdatePatch = yield request<
                RequestRoutePluginUpdatePatch,
                ParamsRoutePluginUpdatePatch,
                ResponseRoutePluginUpdatePatch
            >({
                location: locationRestPluginUpdatePatch,
                params: {
                    slug: this.slug,
                },
                request: data,
            });

            this.fromResponse(result);
        } catch (e: any) {
            console.log(e);

            // Parse error for invalid keys
            if (e.responseJSON?.data?.invalidKeys) {
                this.invalidKeysError = e.responseJSON.data.invalidKeys;
            }

            throw e;
        } finally {
            this.busy = false;
        }
    });

    public skip: () => Promise<void> = flow(function* (this: PluginUpdate) {
        this.busy = true;
        try {
            yield request<
                RequestRoutePluginUpdateSkipPost,
                ParamsRoutePluginUpdateSkipPost,
                ResponseRoutePluginUpdateSkipPost
            >({
                location: locationRestPluginUpdateSkipPost,
                params: {
                    slug: this.slug,
                },
            });
        } catch (e: any) {
            console.log(e);

            // Parse error for invalid keys
            if (e.responseJSON?.data?.invalidKeys) {
                this.invalidKeysError = e.responseJSON.data.invalidKeysError;
            }

            throw e;
        } finally {
            this.busy = false;
        }
    });
}

export { PluginUpdate };
