/**
 * Patches anchor links, giving them additional or alternate functionality.
 * @module Anchor
 * @memberof Builtin.Enhancements.Components
 */

import { getModule, FluxDispatcher } from '@vizality/webpack';
import { Regexes, Protocols } from '@vizality/constants';
import { findInReactTree } from '@vizality/util/react';
import { patch, unpatch } from '@vizality/patcher';

export const labels = [ 'Components', 'Anchor' ];

export default builtin => {
  const Anchor = getModule(m => m.default?.displayName === 'Anchor');
  const { anchor } = getModule('anchor', 'anchorUnderlineOnHover');
  const vizalityRegex = new RegExp(`${Regexes.DISCORD}/vizality`, 'i');
  const vizalityProtocolRegex = new RegExp(`^(${Protocols.BASE})`, 'i');
  const userRegex = new RegExp(`${Regexes.DISCORD}/users/`, 'i');
  const discordRegex = new RegExp(`${Regexes.DISCORD}`, 'i');

  patch('vz-attributes-anchors', Anchor, 'default', (_, res) => {
    try {
      const props = findInReactTree(res, r => r.className?.includes(anchor) && r.href);
      if (!props) {
        return;
      }

      /**
       *
       */
      if (props.href?.startsWith('#')) {
        props.onClick = evt => {
          try {
            evt.preventDefault();
            /**
             * This is bad, but currently it's the only way I really know how to do it.
             * We're adding a timeout here so that we can give the new route page elements
             * (topOfElement and scroller) time to load into the DOM.
             */
            return setTimeout(() => {
              const topOfElement = document.querySelector(`#${props.href.substring(1)}`)?.offsetTop;
              const scroller = document.querySelector('.vz-dashboard-scroller');
              /**
               * If the elements don't exist at the check, just load the page normally as if
               * there was no hash.
               */
              if (!topOfElement || !scroller) {
                return;
              }
              /**
               * Try to set the scroller position to the hash element.
               */
              return scroller.scroll({ top: topOfElement - 80, behavior: 'smooth' });
            }, 250);
          } catch (err) {
            return builtin.error(builtin._labels.concat(labels), err);
          }
        };
      }

      /**
       * Force Vizality route links to open within the app.
       */
      if (vizalityRegex.test(props.href)) {
        const route = props.href?.replace(discordRegex, '');
        props.onClick = evt => {
          try {
            evt.preventDefault();
            vizality.api.routes.navigateTo(route);
          } catch (err) {
            return builtin.error(builtin._labels.concat(labels), err);
          }
        };
      }

      /**
       * Force Vizality protocol links to open within the app.
       */
      if (vizalityProtocolRegex.test(props.href)) {
        const route = props.href?.replace(vizalityProtocolRegex, '');
        props.onClick = evt => {
          try {
            evt.preventDefault();
            vizality.api.routes.navigateTo(`/vizality/${route}`);
          } catch (err) {
            return builtin.error(builtin._labels.concat(labels), err);
          }
        };
      }

      /*
       * Force user links to open in user profile modals within the app.
       */
      if (userRegex.test(props.href)) {
        const userId = props.href?.replace(userRegex, '');
        props.onClick = async evt => {
          try {
            evt.preventDefault();
            if (!userId) {
              return;
            }
            const user = await $discord.users.fetchUser(userId);
            if (!user) {
              return vizality.api.notifications.sendToast({
                id: 'VIZALITY_USER_NOT_FOUND',
                header: 'User Not Found',
                content: 'That user was unable to be located.',
                icon: 'PersonRemove'
              });
            }
            return FluxDispatcher.dirtyDispatch({
              type: $discord.constants.ActionTypes.USER_PROFILE_MODAL_OPEN,
              userId
            });
          } catch (err) {
            return builtin.error(builtin._labels.concat(labels), err);
          }
        };
      }
    } catch (err) {
      return builtin.error(builtin._labels.concat(labels), err);
    }
  });

  return () => unpatch('vz-attributes-anchors');
};
