import { document } from 'global';
import { addons, makeDecorator } from '@storybook/addons';
import { EVENTS, PARAM_KEY } from './constants';

const changeMediaAttribute = (element: HTMLElement, enabled: boolean) => {
  const current = element.getAttribute('media');
  if ((enabled && !current) || (!enabled && current === 'max-width: 1px')) {
    // don't do anything
  } else if (enabled && current === 'max-width: 1px') {
    // remove the attribute
    element.removeAttribute('media');
  } else if (enabled) {
    // add the disable attribute
    const value = current.replace(' and max-width: 1px', '');
    element.setAttribute('media', value);
  } else {
    // modify the existing attribute so it disables
    const value = current ? `${current} and max-width: 1px` : 'max-width: 1px';
    element.setAttribute('media', value);
  }
};

const createElement = (id: string, code: string): HTMLDivElement => {
  const element: HTMLDivElement = document.createElement('div');
  element.setAttribute('id', `storybook-addon-resource_${id}`);
  element.innerHTML = code;
  return element;
};

const getElement = (id: string, code: string) => {
  const found: Element = document.querySelector(`[id="storybook-addon-resource_${id}"]`);
  return { element: found || createElement(id, code), created: !found };
};

const updateElement = (id: string, code: string, value: boolean) => {
  const { element, created } = getElement(id, code);

  element.querySelectorAll('link').forEach((child) => changeMediaAttribute(child, value));
  element.querySelectorAll('style').forEach((child) => changeMediaAttribute(child, value));

  if (created) {
    document.body.appendChild(element);
  }
};

const list: any[] = [];

const setResources = (resources: { code: string; id: string }[]) => {
  const added = resources.filter((i) => !list.find((r) => r.code === i.code));
  const removed = list.filter((i) => !resources.find((r) => r.code === i.code));

  added.forEach((r) => list.push(r));

  resources.forEach((r) => {
    const { id, code } = r;
    updateElement(id, code, true);
  });
  removed.forEach((r) => {
    const { id, code } = r;
    updateElement(id, code, false);
  });
};

export const withCssResources = makeDecorator({
  name: 'withCssResources',
  parameterName: PARAM_KEY,
  skipIfNoParametersOrOptions: true,

  wrapper: (getStory, context, { options, parameters }) => {
    const storyOptions = parameters || options;
    addons.getChannel().on(EVENTS.SET, setResources);

    if (!Array.isArray(storyOptions) && !Array.isArray(storyOptions.cssresources)) {
      throw new Error('The `cssresources` parameter needs to be an Array');
    }

    return getStory(context);
  },
});

if (module && module.hot && module.hot.decline) {
  module.hot.decline();
}
