/**
 * controllers/LinkOptionsModal.js
 *
 * @file Provides controller for LinkOptionsModal component
 *
 * @author Jessie Hildebrandt
 */

/* -------------------------------------------------------------------------- */
/* Local module imports */

import { ShortenedLinksPanel } from '../interfaces/ShortenedLinksPanel.js';

import { cancelRequestsToURL, delayedInterruptableRequest, formDataFromObject, sleep } from '../utils/utils.js';

/* -------------------------------------------------------------------------- */
/* Controller implementation */

/**
 * Controller for LinkOptionsModal component
 */
const LinkOptionsModal = {

    /* ---------------------------------- */
    /* Enums */

    FIELD_STATE: {
        EMPTY: '',
        VALIDATING: 'validating',
        VALID: 'valid',
        INVALID: 'invalid'
    },

    /* ---------------------------------- */
    /* init */

    /**
     * Initialize the controller
     */
    init()
    {

        LinkOptionsModal.originalLinkDest = '';
        LinkOptionsModal.linkDest = '';
        LinkOptionsModal.linkDestState = '';

        LinkOptionsModal.visitCount = 0;

        LinkOptionsModal.isWaiting = true;

    },

    /* ---------------------------------- */
    /* reset */

    /**
     * Reset the controller
     */
    reset()
    {
        LinkOptionsModal.init();
    },

    /* ---------------------------------- */
    /* load */

    /**
     * Load required information about the selected link from the API and populate it into the modal
     *
     * @param {string} linkID - The ID of the link for which the information will be loaded
     */
    async load( linkID )
    {

        // Load the link's data into the controller
        try
        {
            const response = await m.request( `/shorten/api/links/${ linkID }` );
            const link = response.find( link => link.link_id === linkID );
            LinkOptionsModal.originalLinkDest = link.link_dest;
            LinkOptionsModal.linkDest = link.link_dest;
            LinkOptionsModal.visitCount = link.visit_count;
        }
        catch
        {
            m.route.set( '/app' );
        }

        // We're done our work
        LinkOptionsModal.isWaiting = false;
        m.redraw();

    },

    /* ---------------------------------- */
    /* close */

    /**
     * Close the link options modal
     */
    close()
    {
        m.route.set( '/app' );
    },

    /* ---------------------------------- */
    /* openDeleteModal */

    /**
     * Go to the link deletion modal to confirm a deletion operation for the selected link
     *
     * @param {string} linkID - The ID of the link for which to open the options modal
     */
    openDeleteModal( linkID )
    {
        m.route.set( '/app/delete/:linkID', { linkID: linkID } );
    },

    /* ---------------------------------- */
    /* updateLinkDest */

    /**
     * Update the link destination stored in the controller
     *
     * @param {String} value - The value to update the link destination to
     */
    async updateLinkDest( value )
    {

        // If the field was cleared or changed back to its original value, clear its state
        if ( ( LinkOptionsModal.linkDest = value ) === ''
             || LinkOptionsModal.linkDest === LinkOptionsModal.originalLinkDest )
        {
            cancelRequestsToURL( '/shorten/api/validate/link_dest' );
            LinkOptionsModal.linkDestState = LinkOptionsModal.FIELD_STATE.EMPTY;
            return;
        }

        // Attempt to validate the new link destination
        try
        {
            LinkOptionsModal.linkDestState = LinkOptionsModal.FIELD_STATE.VALIDATING;
            await delayedInterruptableRequest( '/shorten/api/validate/link_dest', `?data=${ value }`, 200 );
            LinkOptionsModal.linkDestState = LinkOptionsModal.FIELD_STATE.VALID;
        }
        catch
        {
            LinkOptionsModal.linkDestState = LinkOptionsModal.FIELD_STATE.INVALID;
        }

    },

    /* ---------------------------------- */
    /* canRedirect */

    /**
     * Return true if the current state of the link destination field is valid to submit for redirection
     *
     * @returns {boolean} Whether or not the current link destination field state is valid for submission
     */
    canRedirect()
    {
        return LinkOptionsModal.linkDestState === LinkOptionsModal.FIELD_STATE.VALID;
    },

    /* ---------------------------------- */
    /* tryRedirect */

    /**
     * Attempt to redirect the selected link
     *
     * @param {string} linkID - The ID of the link to redirect
     */
    async tryRedirect( linkID )
    {

        // Signal to the component that activity is occurring
        LinkOptionsModal.isWaiting = true;
        m.redraw();

        // Prevent the input field from disabling and then re-enabling too quickly
        await sleep( 150 );

        // Attempt to redirect the link by submitting a request to the API
        try
        {
            const response = await m.request( {
                method: 'PUT',
                url: `/shorten/api/links/${ linkID }`,
                body: formDataFromObject( { link_dest: LinkOptionsModal.linkDest } ),
                background: true
            } );
        }
        catch
        {}

        // Refresh the redirected link's loaded information and update the state of the input field
        await LinkOptionsModal.load( linkID );
        LinkOptionsModal.updateLinkDest( LinkOptionsModal.linkDest );

        // Refresh the "Shortened links" UI component's list of links
        ShortenedLinksPanel.refresh();

        // We're done our work
        LinkOptionsModal.isWaiting = false;
        m.redraw();

    }

}

/* -------------------------------------------------------------------------- */
/* Export */

export { LinkOptionsModal };
