import Color from 'color';

const colorGaps = {
  darkLight: 0.4,
  highlight: 0.8,
  contrast: 1,
  edgeColor: {
    darkLight: 0.25,
    highlight: 0.1,
  },
};

const darken = (c, percentage) => c.darken(percentage).hex();

const contrast = (c) => {
  const isDark = c.isDark();
  return c
    .mix(Color(isDark ? 'white' : 'black'), colorGaps.contrast)
    .saturate(1)
    .hex();
};

const lighten = (c, percentage) => {
  const isDark = c.lightness() < 0.5;

  if (isDark) {
    return c.lightness(percentage * 100).hex();
  }

  return c.lighten(percentage).hex();
};

const isNearBlack = (color) => color.luminosity() < 0.01;
const isNearWhite = (color) => color.luminosity() > 0.99;

const generateDarkColor = (color, theme) => {
  if (theme === 'dark') {
    return isNearWhite(color)
      ? darken(color, colorGaps.edgeColor.darkLight)
      : lighten(color, colorGaps.darkLight);
  }

  return isNearBlack(color)
    ? lighten(color, colorGaps.edgeColor.darkLight)
    : darken(color, colorGaps.darkLight);
};

const generateLightColor = (color, theme) => {
  if (theme === 'dark') {
    return isNearBlack(color)
      ? lighten(color, colorGaps.edgeColor.darkLight)
      : darken(color, colorGaps.darkLight);
  }

  return isNearWhite(color)
    ? darken(color, colorGaps.edgeColor.darkLight)
    : lighten(color, colorGaps.darkLight);
};

const generateHighlightColor = (color, theme) => {
  if (theme === 'dark') {
    return isNearBlack(color)
      ? lighten(color, colorGaps.edgeColor.highlight)
      : darken(color, colorGaps.highlight);
  }

  return isNearWhite(color)
    ? darken(color, colorGaps.edgeColor.highlight)
    : lighten(color, colorGaps.highlight);
};

export const genColor = (color, theme) => {
  const mainColor = new Color(color.main || color);

  const res = {
    main: mainColor.hex(),
    dark: color.dark || generateDarkColor(mainColor, theme),
    light: color.light || generateLightColor(mainColor, theme),
    highlight: color.highlight || generateHighlightColor(mainColor, theme),
    contrast: color.contrast || contrast(mainColor),
  };

  return res;
};

export const genColors = (colors) =>
  Object.keys(colors).reduce((acc, colorName) => {
    const currentColor = colors[colorName];

    return Object.assign(acc, {
      [colorName]: genColor(currentColor),
    });
  }, {});
