import { ColorToken, fontWeights, NumberToken } from "../tokens";
import { withOpacity } from "../utils/color";
import Theme, { buildPlayer, Syntax } from "./theme";

export interface Accents {
  "red": ColorToken,
  "orange": ColorToken,
  "yellow": ColorToken,
  "green": ColorToken,
  "cyan": ColorToken,
  "blue": ColorToken,
  "violet": ColorToken,
  "magenta": ColorToken,
}

export function createTheme(name: string, isLight: boolean, neutral: ColorToken[], accent: Accents): Theme {
  if (isLight) {
    neutral = [...neutral].reverse();
  }
  let blend = isLight ? 0.12 : 0.24;

  const backgroundColor = {
    100: {
      base: neutral[1],
      hovered: withOpacity(neutral[2], blend),
      active: withOpacity(neutral[2], blend * 1.5),
      focused: withOpacity(neutral[2], blend),
    },
    300: {
      base: neutral[1],
      hovered: withOpacity(neutral[2], blend),
      active: withOpacity(neutral[2], blend * 1.5),
      focused: withOpacity(neutral[2], blend),
    },
    500: {
      base: neutral[0],
      hovered: withOpacity(neutral[1], blend),
      active: withOpacity(neutral[1], blend * 1.5),
      focused: withOpacity(neutral[1], blend),
    },
    on300: {
      base: neutral[0],
      hovered: withOpacity(neutral[1], blend),
      active: withOpacity(neutral[1], blend * 2),
      focused: withOpacity(neutral[1], blend),
    },
    on500: {
      base: neutral[1],
      hovered: withOpacity(neutral[2], blend),
      active: withOpacity(neutral[2], blend * 2),
      focused: withOpacity(neutral[2], blend),
    },
    ok: {
      base: withOpacity(accent.green, 0.15),
      hovered: withOpacity(accent.green, 0.20),
      active: withOpacity(accent.green, 0.25),
      focused: withOpacity(accent.green, 0.20),
    },
    error: {
      base: withOpacity(accent.red, 0.15),
      hovered: withOpacity(accent.red, 0.20),
      active: withOpacity(accent.red, 0.25),
      focused: withOpacity(accent.red, 0.20),
    },
    warning: {
      base: withOpacity(accent.yellow, 0.15),
      hovered: withOpacity(accent.yellow, 0.20),
      active: withOpacity(accent.yellow, 0.25),
      focused: withOpacity(accent.yellow, 0.20),
    },
    info: {
      base: withOpacity(accent.blue, 0.15),
      hovered: withOpacity(accent.blue, 0.20),
      active: withOpacity(accent.blue, 0.25),
      focused: withOpacity(accent.blue, 0.20),
    },
  };

  const borderColor = {
    primary: neutral[0],
    secondary: neutral[1],
    muted: neutral[3],
    focused: neutral[3],
    active: neutral[3],
    ok: withOpacity(accent.green, 0.15),
    error: withOpacity(accent.red, 0.15),
    warning: withOpacity(accent.yellow, 0.15),
    info: withOpacity(accent.blue, 0.15),
  };

  const textColor = {
    primary: neutral[6],
    secondary: neutral[5],
    muted: neutral[5],
    placeholder: neutral[4],
    active: neutral[7],
    feature: accent.blue,
    ok: accent.green,
    error: accent.red,
    warning: accent.yellow,
    info: accent.blue,
  };

  const player = {
    1: buildPlayer(accent.blue),
    2: buildPlayer(accent.green),
    3: buildPlayer(accent.magenta),
    4: buildPlayer(accent.orange),
    5: buildPlayer(accent.violet),
    6: buildPlayer(accent.cyan),
    7: buildPlayer(accent.red),
    8: buildPlayer(accent.yellow),
  };

  const editor = {
    background: backgroundColor[500].base,
    indent_guide: borderColor.muted,
    indent_guide_active: borderColor.secondary,
    line: {
      active: withOpacity(neutral[7], 0.07),
      highlighted: withOpacity(neutral[7], 0.12),
      inserted: backgroundColor.ok.active,
      deleted: backgroundColor.error.active,
      modified: backgroundColor.info.active,
    },
    highlight: {
      selection: player[1].selectionColor,
      occurrence: withOpacity(neutral[7], blend / 2),
      activeOccurrence: withOpacity(neutral[7], blend),
      matchingBracket: backgroundColor[500].active,
      match: withOpacity(accent.violet, blend * 2),
      activeMatch: withOpacity(accent.violet, blend * 3),
      related: backgroundColor[500].focused,
    },
    gutter: {
      primary: textColor.placeholder,
      active: textColor.active,
    },
  };

  const syntax: Syntax = {
    primary: {
      color: neutral[7],
      weight: fontWeights.normal,
    },
    comment: {
      color: neutral[5],
      weight: fontWeights.normal,
    },
    punctuation: {
      color: neutral[5],
      weight: fontWeights.normal,
    },
    constant: {
      color: neutral[4],
      weight: fontWeights.normal,
    },
    keyword: {
      color: accent.blue,
      weight: fontWeights.normal,
    },
    function: {
      color: accent.yellow,
      weight: fontWeights.normal,
    },
    type: {
      color: accent.cyan,
      weight: fontWeights.normal,
    },
    variant: {
      color: accent.blue,
      weight: fontWeights.normal,
    },
    property: {
      color: accent.blue,
      weight: fontWeights.normal,
    },
    enum: {
      color: accent.orange,
      weight: fontWeights.normal,
    },
    operator: {
      color: accent.orange,
      weight: fontWeights.normal,
    },
    string: {
      color: accent.orange,
      weight: fontWeights.normal,
    },
    number: {
      color: accent.green,
      weight: fontWeights.normal,
    },
    boolean: {
      color: accent.green,
      weight: fontWeights.normal,
    },
    predictive: {
      color: textColor.muted,
      weight: fontWeights.normal,
    },
    title: {
      color: accent.yellow,
      weight: fontWeights.bold,
    },
    emphasis: {
      color: textColor.feature,
      weight: fontWeights.normal,
    },
    "emphasis.strong": {
      color: textColor.feature,
      weight: fontWeights.bold,
    },
    linkUri: {
      color: accent.green,
      weight: fontWeights.normal,
      underline: true,
    },
    linkText: {
      color: accent.orange,
      weight: fontWeights.normal,
      italic: true,
    },
  };

  const shadowAlpha: NumberToken = {
    value: blend,
    type: "number",
  };

  return {
    name,
    backgroundColor,
    borderColor,
    textColor,
    iconColor: textColor,
    editor,
    syntax,
    player,
    shadowAlpha,
  };
}