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

import { request } from "../utils/request.js";
import { locationRestConsentDelete } from "../wp-api/consent.delete.js";

import type { ConsentStore } from "../store/consent.js";
import type {
    ParamsRouteConsentDelete,
    RequestRouteConsentDelete,
    ResponseRouteConsentDelete,
} from "../wp-api/consent.delete.js";
import type { ResponseRouteConsentAllGetEntity } from "../wp-api/consentAll.get.js";

class Consent {
    @observable
    public busy = false;

    @observable
    public id: number;

    @observable
    public plugin_version: ResponseRouteConsentAllGetEntity["plugin_version"];

    @observable
    public design_version: ResponseRouteConsentAllGetEntity["design_version"];

    @observable
    public ipv4?: ResponseRouteConsentAllGetEntity["ipv4"];

    @observable
    public ipv6?: ResponseRouteConsentAllGetEntity["ipv6"];

    @observable
    public ipv4_hash: ResponseRouteConsentAllGetEntity["ipv4_hash"];

    @observable
    public ipv6_hash: ResponseRouteConsentAllGetEntity["ipv6_hash"];

    @observable
    public uuid: ResponseRouteConsentAllGetEntity["uuid"];

    @observable
    public previous_decision: ResponseRouteConsentAllGetEntity["previous_decision"];

    @observable
    public decision: ResponseRouteConsentAllGetEntity["decision"];

    @observable
    public decision_labels: ResponseRouteConsentAllGetEntity["decision_labels"];

    @observable
    public created: ResponseRouteConsentAllGetEntity["created"];

    @observable
    public blocker: ResponseRouteConsentAllGetEntity["blocker"];

    @observable
    public blocker_thumbnail: ResponseRouteConsentAllGetEntity["blocker_thumbnail"];

    @observable
    public dnt: ResponseRouteConsentAllGetEntity["dnt"];

    @observable
    public custom_bypass?: ResponseRouteConsentAllGetEntity["custom_bypass"];

    @observable
    public user_country: ResponseRouteConsentAllGetEntity["user_country"];

    @observable
    public revision_hash: ResponseRouteConsentAllGetEntity["revision_hash"];

    @observable
    public revision_independent_hash: ResponseRouteConsentAllGetEntity["revision_independent_hash"];

    @observable
    public button_clicked: ResponseRouteConsentAllGetEntity["button_clicked"];

    @observable
    public context: ResponseRouteConsentAllGetEntity["context"];

    @observable
    public viewport_width: ResponseRouteConsentAllGetEntity["viewport_width"];

    @observable
    public viewport_height: ResponseRouteConsentAllGetEntity["viewport_height"];

    @observable
    public referer: ResponseRouteConsentAllGetEntity["referer"];

    @observable
    public url_imprint: ResponseRouteConsentAllGetEntity["url_imprint"];

    @observable
    public url_privacy_policy: ResponseRouteConsentAllGetEntity["url_privacy_policy"];

    @observable
    public forwarded?: ResponseRouteConsentAllGetEntity["forwarded"];

    @observable
    public forwarded_blocker: ResponseRouteConsentAllGetEntity["forwarded_blocker"];

    @observable
    public previous_tcf_string?: ResponseRouteConsentAllGetEntity["tcf_string"];

    @observable
    public tcf_string?: ResponseRouteConsentAllGetEntity["tcf_string"];

    @observable
    public previous_gcm_consent?: ResponseRouteConsentAllGetEntity["previous_gcm_consent"];

    @observable
    public gcm_consent?: ResponseRouteConsentAllGetEntity["gcm_consent"];

    @observable
    public recorder?: ResponseRouteConsentAllGetEntity["recorder"];

    @observable
    public ui_view?: ResponseRouteConsentAllGetEntity["ui_view"];

    @computed
    public get revision() {
        return this.store.revisions.get(this.revision_hash);
    }

    @computed
    public get revision_independent() {
        return this.store.revisionsIndependent.get(this.revision_independent_hash);
    }

    @computed
    public get custom_bypass_readable() {
        const { custom_bypass } = this;
        return custom_bypass ? custom_bypass.charAt(0).toUpperCase() + custom_bypass.slice(1) : "";
    }

    public readonly store: ConsentStore;

    /**
     * Plain consent from REST API so it can be easily exported.
     */
    public readonly plain: Partial<ResponseRouteConsentAllGetEntity>;

    /**
     * Prepare the entry for JSON export.
     */
    public get export() {
        return JSON.parse(
            JSON.stringify({
                ...this.plain,
                revision: this.revision.data,
                revision_independent: this.revision_independent.data,
            }),
        ) as Consent["plain"] & {
            revision: Consent["revision"]["data"];
            revision_independent: Consent["revision_independent"]["data"];
        };
    }

    public constructor(consent: Partial<ResponseRouteConsentAllGetEntity>, store: ConsentStore) {
        runInAction(() => set(this, consent));
        this.store = store;
        this.plain = consent;
    }

    public delete: () => Promise<void> = flow(function* (this: Consent) {
        this.busy = true;
        try {
            yield request<RequestRouteConsentDelete, ParamsRouteConsentDelete, ResponseRouteConsentDelete>({
                location: locationRestConsentDelete,
                params: {
                    id: this.id,
                },
            });

            yield this.store.fetchAll();
        } catch (e) {
            console.log(e);
            throw e;
        } finally {
            this.busy = false;
        }
    });

    public fetchRevisions() {
        return Promise.all([
            this.store.fetchRevision({
                hash: this.revision_hash,
            }),
            this.store.fetchRevisionIndependent({
                hash: this.revision_independent_hash,
            }),
        ]);
    }
}

export { Consent };
