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

import { SeoOriginalItem } from "../models/seoOriginalItem.js";
import { request } from "../utils/request.js";
import { locationRestSeoAttachmentGet } from "../wp-api/seo-attachment.get.js";
import { locationRestSeoClearSizeDelete } from "../wp-api/seo-clear-size.delete.js";
import { locationRestSeoClearDelete } from "../wp-api/seo-clear.delete.js";
import { locationRestSeoRepair } from "../wp-api/seo-repair.post.js";
import { locationRestSeoStateDelete } from "../wp-api/seo-state.delete.js";
import { locationRestSeoStatePost } from "../wp-api/seo-state.post.js";
import { locationRestSeoGet } from "../wp-api/seo.get.js";

import type { RootStore } from "./stores.js";
import type {
    ParamsRestSeoAttachmentGet,
    RequestRestSeoAttachmentGet,
    ResponseRestSeoAttachmentGet,
} from "../wp-api/seo-attachment.get.js";
import type {
    ParamsRestSeoClearSizeDelete,
    RequestRestSeoClearSizeDelete,
    ResponseRestSeoClearSizeDelete,
} from "../wp-api/seo-clear-size.delete.js";
import type {
    ParamsRestSeoClearDelete,
    RequestRestSeoClearDelete,
    ResponseRestSeoClearDelete,
} from "../wp-api/seo-clear.delete.js";
import type { ParamsRestSeoRepair, RequestRestSeoRepair, ResponseRestSeoRepair } from "../wp-api/seo-repair.post.js";
import type {
    ParamsRestSeoStateDelete,
    RequestRestSeoStateDelete,
    ResponseRestSeoStateDelete,
} from "../wp-api/seo-state.delete.js";
import type {
    ParamsRestSeoStatePost,
    RequestRestSeoStatePost,
    ResponseRestSeoStatePost,
} from "../wp-api/seo-state.post.js";
import type { ParamsRestSeoGet, RequestRestSeoGet, ResponseRestSeoGet } from "../wp-api/seo.get.js";

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

class SeoStore {
    @observable
    public state: boolean;

    @observable
    public count: number;

    @observable
    public busy = false;

    @observable
    public items: SeoOriginalItem[] = [];

    @observable
    public bytes = 0;

    @observable
    public sizes: string[] = [];

    @observable
    public currentAttachment = 0;

    public readonly rootStore: RootStore;

    @computed public get sizeReadable() {
        return humanFileSize(this.bytes || 0);
    }

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

    public fetch: (reset: boolean) => CancellablePromise<void> = flow(function* (this: SeoStore, reset = false) {
        this.busy = true;
        reset === true && (this.items = []);
        reset === true && (this.sizes = []);

        let response: ResponseRestSeoGet & ResponseRestSeoAttachmentGet;

        if (this.currentAttachment > 0) {
            response = yield request<
                RequestRestSeoAttachmentGet,
                ParamsRestSeoAttachmentGet,
                ResponseRestSeoAttachmentGet
            >({
                location: locationRestSeoAttachmentGet,
                params: {
                    skip: this.items.length,
                    id: this.currentAttachment,
                },
            });
        } else {
            response = yield request<RequestRestSeoGet, ParamsRestSeoGet, ResponseRestSeoGet>({
                location: locationRestSeoGet,
                params: {
                    skip: this.items.length,
                },
            });
        }
        const { cnt, items, size, sizes, state } = response;
        items.forEach((o) => this.items.push(new SeoOriginalItem({ ...o, type: "original" }, this)));
        this.state = state;
        this.sizes = sizes;
        this.count = cnt;
        this.bytes = size;
        this.busy = false;
    });

    public repair: () => CancellablePromise<void> = flow(function* (this: SeoStore) {
        yield request<RequestRestSeoRepair, ParamsRestSeoRepair, ResponseRestSeoRepair>({
            location: locationRestSeoRepair,
        });
        this.fetch(true);
    });

    public clear: (size?: string) => CancellablePromise<void> = flow(function* (this: SeoStore, size) {
        if (size) {
            yield request<RequestRestSeoClearSizeDelete, ParamsRestSeoClearSizeDelete, ResponseRestSeoClearSizeDelete>({
                location: locationRestSeoClearSizeDelete,
                params: {
                    size,
                },
            });
        } else {
            yield request<RequestRestSeoClearDelete, ParamsRestSeoClearDelete, ResponseRestSeoClearDelete>({
                location: locationRestSeoClearDelete,
            });
        }
        this.fetch(true);
    });

    public setState: (state: boolean) => CancellablePromise<void> = flow(function* (this: SeoStore, state) {
        this.items = [];
        this.busy = true;
        if (state) {
            yield request<RequestRestSeoStatePost, ParamsRestSeoStatePost, ResponseRestSeoStatePost>({
                location: locationRestSeoStatePost,
            });
        } else {
            yield request<RequestRestSeoStateDelete, ParamsRestSeoStateDelete, ResponseRestSeoStateDelete>({
                location: locationRestSeoStateDelete,
            });
        }
        this.fetch(true);
        this.busy = false;
    });

    public toggleState: () => CancellablePromise<void> = flow(function* (this: SeoStore) {
        yield this.setState(!this.state);
    });

    @action
    public setCurrentAttachment(id: number) {
        this.currentAttachment = id;
    }

    public resetCurrentAttachment() {
        this.setCurrentAttachment(0);
    }
}

export { SeoStore };
