import Component from '@glimmer/component';
import {action} from '@ember/object';
import {htmlSafe} from '@ember/template';
import {inject} from 'ghost-admin/decorators/inject';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking';

export default class GhBillingIframe extends Component {
    @service ajax;
    @service billing;
    @service configManager;
    @service ghostPaths;
    @service limit;
    @service notifications;
    @service session;
    @service stateBridge;

    @inject config;

    @tracked isOwner = null;

    willDestroy() {
        super.willDestroy(...arguments);
        window.removeEventListener('message', this.handleIframeMessage);
    }

    @action
    setup() {
        this.billing.setBillingIframeSrc();
        this.billing.startBillingAppLoadMonitor();
        window.addEventListener('message', this.handleIframeMessage);
    }

    @action
    async handleIframeMessage(event) {
        if (this.isDestroyed || this.isDestroying) {
            return;
        }

        if (!this.billing.isValidBillingIframeMessage(event)) {
            return;
        }

        const data = event.data;

        if (data?.request === 'billingAppReady') {
            this.billing.markBillingAppLoaded(data);

            if (data?.route) {
                this.billing.handleRouteChangeInIframe(data.route);
            }

            return;
        }

        this.billing.recordBillingAppPreReadyMessage(data);

        if (data?.route) {
            this.billing.handleRouteChangeInIframe(data.route);
        }

        if (data?.request === 'token') {
            this._handleTokenRequest();
        }

        if (data?.request === 'forceUpgradeInfo') {
            this._handleForceUpgradeRequest();
        }

        if (data?.subscription) {
            await this._handleSubscriptionUpdate(data);
        }
    }

    _postMessageToBillingIframe(message) {
        const billingIframeWindow = this.billing.getBillingIframe()?.contentWindow;
        const billingAppOrigin = this.billing.getBillingAppOrigin();

        if (!billingIframeWindow || !billingAppOrigin) {
            return;
        }

        billingIframeWindow.postMessage(message, billingAppOrigin);
    }

    _handleTokenRequest() {
        const handleNoPermission = () => {
            // no permission means the current user requesting the token is not the owner of the site.
            this.isOwner = false;

            // Avoid letting the BMA waiting for a message and send an empty token response instead
            this._postMessageToBillingIframe({
                request: 'token',
                response: null
            });
        };

        if (!this.session.user?.isOwnerOnly) {
            handleNoPermission();
            return;
        }

        const ghostIdentityUrl = this.ghostPaths.url.api('identities');
        this.ajax.request(ghostIdentityUrl).then((response) => {
            const token = response?.identities?.[0]?.token;
            this._postMessageToBillingIframe({
                request: 'token',
                response: token
            });

            this.isOwner = true;
        }).catch((error) => {
            if (error.payload?.errors?.[0]?.type === 'NoPermissionError') {
                handleNoPermission();
            } else {
                throw error;
            }
        });
    }

    _handleForceUpgradeRequest() {
        // Send BMA requested information about forceUpgrade and owner name/email
        let ownerUser = null;
        const owner = this.billing.ownerUser;

        if (owner) {
            ownerUser = {
                name: owner?.name,
                email: owner?.email
            };
        }
        this._postMessageToBillingIframe({
            request: 'forceUpgradeInfo',
            response: {
                forceUpgrade: this.config.hostSettings?.forceUpgrade,
                isOwner: this.isOwner,
                ownerUser
            }
        });
    }

    async _handleSubscriptionUpdate(data) {
        // Refresh config which includes billing limits and other plan-related settings
        try {
            await this.configManager.fetch();
        } catch (e) {
            // proceed anyway so we at least re-evaluate limits and nudge Admin-X to refetch
        }

        // Reload the limit service to ensure all admin pages can enforce limits
        this.limit.reload();

        this.stateBridge.triggerSubscriptionChange(data);

        // Invalidate React Query cache for config data in admin-x-settings
        if (window?.adminXQueryClient?.invalidateQueries && typeof window.adminXQueryClient.invalidateQueries === 'function') {
            try {
                // React Query v5+
                window.adminXQueryClient.refetchQueries({queryKey: ['ConfigResponseType']}).catch(() => {});
                window.adminXQueryClient.refetchQueries({queryKey: ['SettingsResponseType']}).catch(() => {});
            } catch (_) {
                // TODO: remove this fallback when Admin-X-Settings updates to React Query v5+ (@tanstack/react-query)
                // React Query v4 fallback
                window.adminXQueryClient.refetchQueries(['ConfigResponseType']).catch(() => {});
                window.adminXQueryClient.refetchQueries(['SettingsResponseType']).catch(() => {});
            }
        }

        this.billing.subscription = data.subscription;
        this.billing.checkoutRoute = data?.checkoutRoute ?? '/plans';

        if (data.subscription.status === 'active' && this.config.hostSettings?.forceUpgrade) {
            // config might not be updated after a subscription has been set to active.
            // Until then assume the forceUpgrade is over and the subscription
            // was activated successfully.
            this.config.hostSettings.forceUpgrade = false;
        }

        // Detect if the current subscription is in a grace state and render a notification
        if (data.subscription.status === 'past_due' || data.subscription.status === 'unpaid') {
            // This notification needs to be shown to every user regardless their permissions to see billing
            this.notifications.showAlert(htmlSafe(`Your billing details need updating. The site owner must <a href="${this.billing.billingRouteRoot}">update payment information</a> to avoid suspension.`), {type: 'error', key: 'billing.overdue'});
        } else {
            this.notifications.closeAlerts('billing.overdue');
        }
        // Detect if the current member limits are exceeded and render a notification
        if (
            data?.exceededLimits
            && data?.exceededLimits.length
            && data?.exceededLimits.indexOf('members') >= 0
            && data?.checkoutRoute
        ) {
            // The action param will be picked up on a transition from the router and can
            // then send the destination route as a message to the BMA, which then handles the redirect.
            const checkoutAction = this.billing.billingRouteRoot + '?action=checkout';

            this.notifications.showAlert(htmlSafe(`Your audience has grown! To continue publishing, the site owner must <a href="${checkoutAction}">confirm pricing for this number of members</a>.`), {type: 'warn', key: 'billing.exceeded'});
        } else {
            this.notifications.closeAlerts('billing.exceeded');
        }
    }
}
