import { describe, expect, it } from "vitest";
import {
  compositeHexColor,
  createCoolorsContrastUrl,
  getContrastRatio
} from "./color-contrast";
import {
  MAP_STYLE_TOKENS
} from "./map-colors";
import { createBaseStyle } from "./sources";

const sourceColors = Object.values(MAP_STYLE_TOKENS.supply);
const mapBackgrounds = [
  MAP_STYLE_TOKENS.canvas.primary,
  MAP_STYLE_TOKENS.canvas.secondary,
  MAP_STYLE_TOKENS.canvas.secondaryAlt
];

describe("map color contrast", () => {
  it("calculates WCAG contrast and alpha composites", () => {
    expect(getContrastRatio("#000000", "#FFFFFF")).toBe(21);
    expect(compositeHexColor("#0F766E", "#F9FAFB", 0.88)).toBe("#2B867F");
    expect(() => compositeHexColor("#0F766E", "#F9FAFB", 1.01)).toThrow(RangeError);
  });

  it("generates a direct Coolors contrast-checker link", () => {
    expect(createCoolorsContrastUrl("#0F766E", "#F9FAFB")).toBe(
      "https://coolors.co/contrast-checker/0f766e-f9fafb"
    );
  });

  it("keeps rendered source colors above 3:1 on every map background", () => {
    sourceColors.forEach((sourceColor) => {
      mapBackgrounds.forEach((background) => {
        const renderedColor = compositeHexColor(
          sourceColor,
          background,
          MAP_STYLE_TOKENS.opacity.core
        );

        expect(
          getContrastRatio(renderedColor, background),
          createCoolorsContrastUrl(renderedColor, background)
        ).toBeGreaterThanOrEqual(3);
      });
    });
  });

  it("keeps selected outlines above 4.5:1 on every map background", () => {
    mapBackgrounds.forEach((background) => {
      const selectedColor = MAP_STYLE_TOKENS.state.selected;
      expect(
        getContrastRatio(selectedColor, background),
        createCoolorsContrastUrl(selectedColor, background)
      ).toBeGreaterThanOrEqual(4.5);
    });
  });

  it("keeps operational states above 3:1 on every map background", () => {
    const operationalColors = [
      MAP_STYLE_TOKENS.state.success,
      MAP_STYLE_TOKENS.state.risk,
      MAP_STYLE_TOKENS.state.incident,
      MAP_STYLE_TOKENS.state.inactive,
      MAP_STYLE_TOKENS.state.agent
    ];

    operationalColors.forEach((stateColor) => {
      mapBackgrounds.forEach((background) => {
        expect(
          getContrastRatio(stateColor, background),
          createCoolorsContrastUrl(stateColor, background)
        ).toBeGreaterThanOrEqual(3);
      });
    });
  });

  it("keeps inactive supply assets above 3:1 and applies the primary map background", () => {
    mapBackgrounds.forEach((background) => {
      const renderedColor = compositeHexColor(
        MAP_STYLE_TOKENS.state.inactive,
        background,
        MAP_STYLE_TOKENS.opacity.core
      );
      expect(getContrastRatio(renderedColor, background)).toBeGreaterThanOrEqual(3);
    });

    const backgroundLayer = createBaseStyle().layers?.find((layer) => layer.id === "background");
    if (backgroundLayer?.type !== "background") {
      throw new Error("Expected the base style to contain a background layer.");
    }
    expect(backgroundLayer.paint?.["background-color"]).toBe(MAP_STYLE_TOKENS.canvas.primary);
  });
});
