import {Theme} from '@emotion/react';

import {DurationDisplay} from 'sentry/components/performance/waterfall/types';
import {CHART_PALETTE} from 'sentry/constants/chartPalette';
import {space} from 'sentry/styles/space';

import {getSpanBarColours, SpanBarType} from './constants';

export const getBackgroundColor = ({
  showStriping,
  showDetail,
  theme,
}: {
  theme: Theme;
  showDetail?: boolean;
  showStriping?: boolean;
}) => {
  if (showDetail) {
    return theme.textColor;
  }

  if (showStriping) {
    return theme.backgroundSecondary;
  }

  return theme.background;
};

export function getHatchPattern(spanBarType: SpanBarType | undefined, theme: Theme) {
  if (spanBarType) {
    const {primary, alternate} = getSpanBarColours(spanBarType, theme);

    return `
      background-image: linear-gradient(135deg,
        ${alternate},
        ${alternate} 2.5px,
        ${primary} 2.5px,
        ${primary} 5px,
        ${alternate} 6px,
        ${alternate} 8px,
        ${primary} 8px,
        ${primary} 11px,
        ${alternate} 11px,
        ${alternate} 14px,
        ${primary} 14px,
        ${primary} 16.5px,
        ${alternate} 16.5px,
        ${alternate} 19px,
        ${primary} 20px
      );
      background-size: 16px 16px;
    `;
  }

  return null;
}

export const getDurationPillAlignment = ({
  durationDisplay,
}: {
  durationDisplay: DurationDisplay;
  theme: Theme;
  spanBarType?: SpanBarType;
}) => {
  switch (durationDisplay) {
    case 'left':
      return `right: calc(100% + ${space(0.5)});`;
    case 'right':
      return `left: calc(100% + ${space(0.75)});`;
    default:
      return `
        right: ${space(0.75)};
      `;
  }
};

export const getDurationPillColours = ({
  durationDisplay,
  theme,
  showDetail,
  spanBarType,
}: {
  durationDisplay: DurationDisplay;
  showDetail: boolean;
  theme: Theme;
  spanBarType?: SpanBarType;
}) => {
  if (durationDisplay === 'inset') {
    const {alternate, insetTextColour} = getSpanBarColours(spanBarType, theme);
    return `background: ${alternate}; color: ${insetTextColour};`;
  }

  return `color: ${showDetail ? theme.gray200 : theme.gray300};`;
};

export const getToggleTheme = ({
  theme,
  isExpanded,
  disabled,
  errored,
  isSpanGroupToggler,
  spanBarType,
}: {
  disabled: boolean;
  errored: boolean;
  isExpanded: boolean;
  theme: Theme;
  isSpanGroupToggler?: boolean;
  spanBarType?: SpanBarType;
}) => {
  if (spanBarType) {
    const {primary} = getSpanBarColours(spanBarType, theme);
    return `
    background: ${primary};
    border: 2px solid ${theme.button.default.border};
    color: ${theme.button.primary.color};
    cursor: pointer;
  `;
  }

  const buttonTheme = isExpanded ? theme.button.default : theme.button.primary;
  const errorTheme = theme.button.danger;

  const background = errored
    ? isExpanded
      ? buttonTheme.background
      : errorTheme.background
    : buttonTheme.background;
  const border = errored ? errorTheme.background : buttonTheme.border;
  const color = errored
    ? isExpanded
      ? errorTheme.background
      : buttonTheme.color
    : buttonTheme.color;

  if (isSpanGroupToggler) {
    return `
    background: ${theme.blue300};
    border: 2px solid ${theme.button.default.border};
    color: ${color};
    cursor: pointer;
  `;
  }

  if (disabled) {
    return `
    background: ${background};
    border: 2px solid ${border};
    color: ${color};
    cursor: default;
  `;
  }

  return `
    background: ${background};
    border: 2px solid ${border};
    color: ${color};
  `;
};

export const getDurationDisplay = ({
  width,
  left,
}: {
  left: undefined | number;
  width: undefined | number;
}): DurationDisplay => {
  const spaceNeeded = 0.3;

  if (left === undefined || width === undefined) {
    return 'inset';
  }
  if (left + width < 1 - spaceNeeded) {
    return 'right';
  }
  if (left > spaceNeeded) {
    return 'left';
  }
  return 'inset';
};

export const getHumanDuration = (duration: number): string => {
  // note: duration is assumed to be in seconds
  const durationMs = duration * 1000;
  return `${durationMs.toLocaleString(undefined, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  })}ms`;
};

export const toPercent = (value: number) => `${(value * 100).toFixed(3)}%`;

export const toRoundedPercent = (value: number) => `${Math.round(value * 100)}%`;

type Rect = {
  height: number;
  width: number;
  // x and y are left/top coords respectively
  x: number;
  y: number;
};

// get position of element relative to top/left of document
export const getOffsetOfElement = (element: Element) => {
  // left and top are relative to viewport
  const {left, top} = element.getBoundingClientRect();

  // get values that the document is currently scrolled by
  const scrollLeft = window.pageXOffset;
  const scrollTop = window.pageYOffset;

  return {x: left + scrollLeft, y: top + scrollTop};
};

export const rectOfContent = (element: Element): Rect => {
  const {x, y} = getOffsetOfElement(element);

  // offsets for the border and any scrollbars (clientLeft and clientTop),
  // and if the element was scrolled (scrollLeft and scrollTop)
  //
  // NOTE: clientLeft and clientTop does not account for any margins nor padding
  const contentOffsetLeft = element.clientLeft - element.scrollLeft;
  const contentOffsetTop = element.clientTop - element.scrollTop;

  return {
    x: x + contentOffsetLeft,
    y: y + contentOffsetTop,
    width: element.scrollWidth,
    height: element.scrollHeight,
  };
};

export const clamp = (value: number, min: number, max: number): number => {
  if (value < min) {
    return min;
  }
  if (value > max) {
    return max;
  }
  return value;
};

const getLetterIndex = (letter: string): number => {
  const index = 'abcdefghijklmnopqrstuvwxyz'.indexOf(letter) || 0;
  return index === -1 ? 0 : index;
};

const colorsAsArray = Object.keys(CHART_PALETTE).map(key => CHART_PALETTE[17][key]);

export const barColors = {
  default: CHART_PALETTE[17][4],
  transaction: CHART_PALETTE[17][8],
  http: CHART_PALETTE[17][10],
  db: CHART_PALETTE[17][17],
};

export const pickBarColor = (input: string | undefined): string => {
  // We pick the color for span bars using the first three letters of the op name.
  // That way colors stay consistent between transactions.

  if (!input || input.length < 3) {
    return CHART_PALETTE[17][4];
  }

  if (barColors[input]) {
    return barColors[input];
  }

  const letterIndex1 = getLetterIndex(input.slice(0, 1));
  const letterIndex2 = getLetterIndex(input.slice(1, 2));
  const letterIndex3 = getLetterIndex(input.slice(2, 3));
  const letterIndex4 = getLetterIndex(input.slice(3, 4));

  return colorsAsArray[
    (letterIndex1 + letterIndex2 + letterIndex3 + letterIndex4) % colorsAsArray.length
  ];
};
