import { readFileSync } from "node:fs";
import { join } from "node:path";

const statusTones = ["neutral", "info", "success", "warning", "danger"] as const;

describe("semantic status language", () => {
  it("keeps the production status foregrounds above 4.5:1", () => {
    const styles = readFileSync(join(process.cwd(), "src/styles.css"), "utf8");

    statusTones.forEach((tone) => {
      const soft = readOklchToken(styles, `--status-${tone}-soft`);
      const foreground = readOklchToken(styles, `--status-${tone}-foreground`);
      expect(getOklchContrastRatio(foreground, soft), tone).toBeGreaterThanOrEqual(4.5);
    });
  });

  it("defines the complete softened OKLCH token set", () => {
    const styles = readFileSync(join(process.cwd(), "src/styles.css"), "utf8");

    statusTones.forEach((tone) => {
      expect(styles).toContain(`--status-${tone}-soft:`);
      expect(styles).toContain(`--status-${tone}-border:`);
      expect(styles).toContain(`--status-${tone}-foreground:`);
      expect(styles).toContain(`--status-${tone}-mark:`);
      expect(styles).toContain(`.status-tone-${tone}`);
    });
  });

  it("stops shared status motion when reduced motion is requested", () => {
    const styles = readFileSync(join(process.cwd(), "src/styles.css"), "utf8");

    expect(styles).toMatch(
      /@media \(prefers-reduced-motion: reduce\)[\s\S]*?\.status-dot\[data-activity="live"\][\s\S]*?animation:\s*none/
    );
  });

  it("does not derive Agent connection styling from localized copy", () => {
    const agentHook = readFileSync(
      join(process.cwd(), "src/features/workbench/hooks/use-workbench-agent.ts"),
      "utf8"
    );
    const agentPanel = readFileSync(
      join(process.cwd(), "src/features/agent/components/agent-command-panel.tsx"),
      "utf8"
    );

    expect(agentPanel).not.toMatch(/statusLabel\.(?:includes|match|startsWith)/);
    expect(agentPanel).not.toContain("getAgentConnection");
    expect(agentHook).not.toContain("runtimeAvailability");
    expect(agentPanel).toContain("AgentConnectionStatus");
  });
});

type OklchColor = {
  lightness: number;
  chroma: number;
  hue: number;
};

function readOklchToken(styles: string, token: string): OklchColor {
  const match = styles.match(
    new RegExp(`${token}:\\s*oklch\\((\\d+(?:\\.\\d+)?)%\\s+(\\d+(?:\\.\\d+)?)\\s+(\\d+(?:\\.\\d+)?)\\)`)
  );
  if (!match) {
    throw new Error(`Missing OKLCH token: ${token}`);
  }
  return {
    lightness: Number(match[1]) / 100,
    chroma: Number(match[2]),
    hue: Number(match[3])
  };
}

function getOklchContrastRatio(foreground: OklchColor, background: OklchColor) {
  const foregroundLuminance = getOklchRelativeLuminance(foreground);
  const backgroundLuminance = getOklchRelativeLuminance(background);
  const lighter = Math.max(foregroundLuminance, backgroundLuminance);
  const darker = Math.min(foregroundLuminance, backgroundLuminance);
  return (lighter + 0.05) / (darker + 0.05);
}

function getOklchRelativeLuminance({ lightness, chroma, hue }: OklchColor) {
  const hueRadians = (hue * Math.PI) / 180;
  const a = chroma * Math.cos(hueRadians);
  const b = chroma * Math.sin(hueRadians);
  const lPrime = lightness + 0.3963377774 * a + 0.2158037573 * b;
  const mPrime = lightness - 0.1055613458 * a - 0.0638541728 * b;
  const sPrime = lightness - 0.0894841775 * a - 1.291485548 * b;
  const l = lPrime ** 3;
  const m = mPrime ** 3;
  const s = sPrime ** 3;
  const red = clampLinearRgb(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s);
  const green = clampLinearRgb(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s);
  const blue = clampLinearRgb(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s);
  return 0.2126 * red + 0.7152 * green + 0.0722 * blue;
}

function clampLinearRgb(value: number) {
  return Math.min(1, Math.max(0, value));
}
