import type { Tokens } from "@faulty/tokens/generator";

const EXPECTED = {
  accents: ["primary", "background", "foreground", "hover", "active", "text", "translucent"],
  colors: [
    "background.primary",
    "background.primary",
    "background.secondary",
    "background.tertiary",
    "background.accent",
    "background.floating",
    "background.highlight",
    "background.mod.backdrop",
    "background.mod.subtle",
    "border.primary",
    "border.subtle",
    "control.background",
    "control.foreground",
    "interactive.normal",
    "interactive.hover",
    "interactive.active",
    "interactive.background.hover",
    "interactive.background.active",
    "text.normal",
    "text.secondary",
    "text.success",
    "text.info",
    "text.warning",
    "text.danger",
    "text.default",
    "text.accent",
    "text.link",
    "status.success.background",
    "status.success.foreground",
    "status.success.hover",
    "status.success.active",
    "status.success.translucent",
    "status.warning.background",
    "status.warning.foreground",
    "status.warning.hover",
    "status.warning.active",
    "status.warning.translucent",
    "status.danger.background",
    "status.danger.foreground",
    "status.danger.hover",
    "status.danger.active",
    "status.danger.translucent",
    "status.info.background",
    "status.info.foreground",
    "status.info.hover",
    "status.info.active",
    "status.info.translucent",
    "status.default.background",
    "status.default.foreground",
    "status.default.hover",
    "status.default.active",
    "status.default.translucent",
  ],
  fonts: ["normal", "accent", "monospace"],
  spaces: ["xxxs", "xxs", "xs", "sm", "md", "lg", "xl", "xxl", "xxxl"],
  radii: ["flat", "minimal", "normal", "large", "full"],
};

/**
 * Validate that all of the necessary tokens for GDQ Design to function
 * are present in the given token set.
 */
export function validateTokens(tokens: Tokens): Tokens {
  const errors = [];

  for (const accent of tokens.accents) {
    for (const expected of EXPECTED.accents) {
      if (!accent.tokens.includes(`accent.${expected}`)) {
        errors.push({
          type: "accentToken",
          description: `Accent "${accent.name}" does not define a token value for ${expected}`,
        });
      }
    }
  }

  for (const theme of tokens.themes) {
    for (const expected of EXPECTED.colors) {
      if (theme.colors[expected] == null) {
        errors.push({
          type: "themeColor",
          description: `Token ${expected} is not defined for theme ${theme.name}`,
        });
      }
    }
  }

  const fontNames = tokens.fontStacks.map((stack) => stack.name);
  for (const expected of EXPECTED.fonts) {
    if (!fontNames.includes(expected)) {
      errors.push({
        type: "font",
        description: `Font token "${expected}" does not have a definition`,
      });
    }
  }
  const spaceNames = tokens.spaces.map((stack) => stack.name);
  for (const expected of EXPECTED.spaces) {
    if (!spaceNames.includes(expected)) {
      errors.push({
        type: "space",
        description: `Spacing token "${expected}" does not have a definition`,
      });
    }
  }
  const radiiNames = tokens.radii.map((stack) => stack.name);
  for (const expected of EXPECTED.radii) {
    if (!radiiNames.includes(expected)) {
      errors.push({
        type: "radius",
        description: `Radius ${expected} does not have a definition`,
      });
    }
  }

  if (errors.length > 0) {
    console.error(errors);
    throw errors;
  }

  return tokens;
}
