import { expect, test } from "bun:test";
import { consensusMetrics } from "./consensus";
import type { KeywordSource, SourceMetrics } from "./types";

const m = (
  partial: Partial<Record<KeywordSource, Partial<SourceMetrics>>>,
): Partial<Record<KeywordSource, SourceMetrics>> =>
  partial as Partial<Record<KeywordSource, SourceMetrics>>;

test("no SEO source → all null", () => {
  expect(consensusMetrics(m({}))).toEqual({
    volume: null,
    kd: null,
    cpc: null,
  });
  expect(consensusMetrics(m({ gsc: { volume: 999 } }))).toEqual({
    volume: null,
    kd: null,
    cpc: null,
  });
});

test("one source → its value", () => {
  expect(
    consensusMetrics(m({ semrush: { volume: 1000, kd: 40, cpc: 2 } })),
  ).toEqual({ volume: 1000, kd: 40, cpc: 2 });
});

test("two sources → mean of the two (even count median)", () => {
  expect(
    consensusMetrics(
      m({
        semrush: { volume: 900, kd: 30, cpc: 1 },
        mangools: { volume: 1100, kd: 50, cpc: 3 },
      }),
    ),
  ).toEqual({ volume: 1000, kd: 40, cpc: 2 });
});

test("three sources → middle value (odd count median)", () => {
  expect(
    consensusMetrics(
      m({
        semrush: { volume: 900, kd: 30, cpc: 1 },
        mangools: { volume: 1400, kd: 50, cpc: 5 },
        ahrefs: { volume: 1000, kd: 45, cpc: 2 },
      }),
    ),
  ).toEqual({ volume: 1000, kd: 45, cpc: 2 });
});

test("per-field independence: a field missing on one source is ignored for that field", () => {
  const r = consensusMetrics(
    m({
      semrush: { volume: 1000, kd: 40, cpc: 2 },
      mangools: { volume: 2000 } as Partial<SourceMetrics>,
    }),
  );
  expect(r.volume).toBe(1500);
  expect(r.kd).toBe(40);
  expect(r.cpc).toBe(2);
});

// ELEVA-54 — manual source counts in the consensus
test("manual + tool source → mean of both (even count median)", () => {
  expect(
    consensusMetrics(
      m({
        semrush: { volume: 100, kd: 20, cpc: 1 },
        manual: { volume: 300, kd: 60, cpc: 3 },
      }),
    ),
  ).toEqual({ volume: 200, kd: 40, cpc: 2 });
});

test("manual alone → its value", () => {
  expect(
    consensusMetrics(m({ manual: { volume: 500, kd: 35, cpc: 1.5 } })),
  ).toEqual({ volume: 500, kd: 35, cpc: 1.5 });
});

test("gsc alone still yields null (gsc excluded from consensus)", () => {
  expect(consensusMetrics(m({ gsc: { volume: 999 } }))).toEqual({
    volume: null,
    kd: null,
    cpc: null,
  });
});
