import { colorToRGBA, hslaToRGBA, rgbaToHex, rgbaToHSLA } from "../../helpers/color";
import { Color } from "../../types/misc";
import { XLSXColor } from "../../types/xlsx";
import { AUTO_COLOR } from "../constants";
import { XLSX_INDEXED_COLORS } from "./conversion_maps";

/**
 * Most of the functions could stay private, but are exported for testing purposes
 */

/**
 *
 * Extract the color referenced inside of an XML element and return it as an hex string #RRGGBBAA (or #RRGGBB
 * if alpha = FF)
 *
 *  The color is an attribute of the element that can be :
 *  - rgb : an rgb string
 *  - theme : a reference to a theme element
 *  - auto : automatic coloring. Return const AUTO_COLOR in constants.ts.
 *  - indexed : a legacy indexing scheme for colors. The only value that should be present in a xlsx is
 *      64 = System Foreground, that we can replace with AUTO_COLOR.
 */
export function convertColor(xlsxColor: XLSXColor | undefined): Color | undefined {
  if (!xlsxColor) {
    return undefined;
  }
  let rgb: string;
  if (xlsxColor.rgb) {
    rgb = xlsxColor.rgb;
  } else if (xlsxColor.auto) {
    rgb = AUTO_COLOR;
  } else if (xlsxColor.indexed) {
    rgb = XLSX_INDEXED_COLORS[xlsxColor.indexed];
  } else {
    return undefined;
  }

  rgb = xlsxColorToHEXA(rgb);

  if (xlsxColor.tint) {
    rgb = applyTint(rgb, xlsxColor.tint);
  }
  rgb = rgb.toUpperCase();

  // Remove unnecessary alpha
  if (rgb.length === 9 && rgb.endsWith("FF")) {
    rgb = rgb.slice(0, 7);
  }
  return rgb;
}

/**
 * Convert a hex color AARRGGBB (or RRGGBB)(representation inside XLSX Xmls) to a standard js color
 * representation #RRGGBBAA
 */
function xlsxColorToHEXA(color: Color): Color {
  if (color.length === 6) {
    return "#" + color + "FF";
  }
  return "#" + color.slice(2) + color.slice(0, 2);
}

/**
 * Apply luminance modification and offset to a color (see OpenXml spec §20.1.2.3.13 lumMod and §20.1.2.3.14 lumOff).
 * Both lumMod and lumOff are fractions (raw XML values divided by 100000).
 */
export function applyLumModOff(color: Color, lumMod: number, lumOff: number): Color {
  const rgba = colorToRGBA(color);
  const hsla = rgbaToHSLA(rgba);
  hsla.l = Math.min(100, Math.max(0, hsla.l * lumMod + lumOff * 100));
  return rgbaToHex(hslaToRGBA(hsla));
}

/**
 *  Apply tint to a color (see OpenXml spec §18.3.1.15);
 */
function applyTint(color: Color, tint: number): Color {
  const rgba = colorToRGBA(color);
  const hsla = rgbaToHSLA(rgba);

  if (tint < 0) {
    hsla.l = hsla.l * (1 + tint);
  }
  if (tint > 0) {
    hsla.l = hsla.l * (1 - tint) + (100 - 100 * (1 - tint));
  }

  return rgbaToHex(hslaToRGBA(hsla));
}

/**
 * Convert a hex + alpha color string to an integer representation. Also remove the alpha.
 *
 * eg. #FF0000FF => 4278190335
 */
export function hexaToInt(hex: Color) {
  if (hex.length === 9) {
    hex = hex.slice(0, 7);
  }
  return parseInt(hex.replace("#", ""), 16);
}

/**
 * When defining style (fontColor, borderColor for instance)
 * Excel will specify rgb="FF000000"
 * In that case, We should not consider this value as user-defined but
 * rather like an instruction: "Use your system default"
 */
export const DEFAULT_SYSTEM_COLOR = "FF000000";
