import { afterEach, describe, expect, it, vi } from "vitest";
import type { TelegramNetworkConfig } from "../../../src/config/types.telegram.js";
import {
  resetTelegramNetworkConfigStateForTests,
  resolveTelegramAutoSelectFamilyDecision,
  resolveTelegramDnsResultOrderDecision,
} from "./network-config.js";

// Mock isWSL2Sync at the top level
vi.mock("../../../src/infra/wsl.js", () => ({
  isWSL2Sync: vi.fn(() => false),
}));

import { isWSL2Sync } from "../../../src/infra/wsl.js";

describe("resolveTelegramAutoSelectFamilyDecision", () => {
  afterEach(() => {
    vi.restoreAllMocks();
    resetTelegramNetworkConfigStateForTests();
  });

  it.each([
    {
      name: "prefers env enable over env disable",
      env: {
        OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY: "1",
        OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1",
      },
      expected: {
        value: true,
        source: "env:OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY",
      },
    },
    {
      name: "uses env disable when set",
      env: { OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1" },
      expected: {
        value: false,
        source: "env:OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY",
      },
    },
    {
      name: "prefers env enable over config",
      env: { OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY: "1" },
      network: { autoSelectFamily: false },
      expected: {
        value: true,
        source: "env:OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY",
      },
    },
    {
      name: "prefers env disable over config",
      env: { OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1" },
      network: { autoSelectFamily: true },
      expected: {
        value: false,
        source: "env:OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY",
      },
    },
    {
      name: "uses config override when provided",
      env: {},
      network: { autoSelectFamily: true },
      expected: { value: true, source: "config" },
    },
  ])("$name", ({ env, network, expected }) => {
    const decision = resolveTelegramAutoSelectFamilyDecision({
      env,
      network,
      nodeMajor: 22,
    });
    expect(decision).toEqual(expected);
  });

  it("defaults to enable on Node 22", () => {
    const decision = resolveTelegramAutoSelectFamilyDecision({ env: {}, nodeMajor: 22 });
    expect(decision).toEqual({ value: true, source: "default-node22" });
  });

  it("returns null when no decision applies", () => {
    const decision = resolveTelegramAutoSelectFamilyDecision({ env: {}, nodeMajor: 20 });
    expect(decision).toEqual({ value: null });
  });

  describe("WSL2 detection", () => {
    it.each([
      {
        name: "disables autoSelectFamily on WSL2",
        env: {},
        expected: { value: false, source: "default-wsl2" },
      },
      {
        name: "respects config override on WSL2",
        env: {},
        network: { autoSelectFamily: true },
        expected: { value: true, source: "config" },
      },
      {
        name: "respects env override on WSL2",
        env: { OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY: "1" },
        expected: {
          value: true,
          source: "env:OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY",
        },
      },
      {
        name: "uses Node 22 default when not on WSL2",
        wsl2: false,
        env: {},
        expected: { value: true, source: "default-node22" },
      },
    ])("$name", ({ env, network, expected, wsl2 = true }) => {
      vi.mocked(isWSL2Sync).mockReturnValue(wsl2);
      const decision = resolveTelegramAutoSelectFamilyDecision({
        env,
        network,
        nodeMajor: 22,
      });
      expect(decision).toEqual(expected);
    });

    it("memoizes WSL2 detection across repeated defaults", () => {
      vi.mocked(isWSL2Sync).mockReturnValue(true);
      vi.mocked(isWSL2Sync).mockClear();
      vi.mocked(isWSL2Sync).mockReturnValue(false);
      resolveTelegramAutoSelectFamilyDecision({ env: {}, nodeMajor: 22 });
      resolveTelegramAutoSelectFamilyDecision({ env: {}, nodeMajor: 22 });
      expect(isWSL2Sync).toHaveBeenCalledTimes(1);
    });
  });
});

describe("resolveTelegramDnsResultOrderDecision", () => {
  it.each([
    {
      name: "uses env override when provided",
      env: { OPENCLAW_TELEGRAM_DNS_RESULT_ORDER: "verbatim" },
      nodeMajor: 22,
      expected: {
        value: "verbatim",
        source: "env:OPENCLAW_TELEGRAM_DNS_RESULT_ORDER",
      },
    },
    {
      name: "normalizes trimmed env values",
      env: { OPENCLAW_TELEGRAM_DNS_RESULT_ORDER: "  IPV4FIRST  " },
      nodeMajor: 20,
      expected: {
        value: "ipv4first",
        source: "env:OPENCLAW_TELEGRAM_DNS_RESULT_ORDER",
      },
    },
    {
      name: "uses config override when provided",
      network: { dnsResultOrder: "ipv4first" },
      nodeMajor: 20,
      expected: { value: "ipv4first", source: "config" },
    },
    {
      name: "normalizes trimmed config values",
      network: { dnsResultOrder: "  Verbatim  " } as TelegramNetworkConfig & {
        dnsResultOrder: string;
      },
      nodeMajor: 20,
      expected: { value: "verbatim", source: "config" },
    },
    {
      name: "ignores invalid env values and falls back to config",
      env: { OPENCLAW_TELEGRAM_DNS_RESULT_ORDER: "bogus" },
      network: { dnsResultOrder: "ipv4first" },
      nodeMajor: 20,
      expected: { value: "ipv4first", source: "config" },
    },
    {
      name: "ignores invalid env and config values before applying Node 22 default",
      env: { OPENCLAW_TELEGRAM_DNS_RESULT_ORDER: "bogus" },
      network: { dnsResultOrder: "invalid" } as TelegramNetworkConfig & { dnsResultOrder: string },
      nodeMajor: 22,
      expected: { value: "ipv4first", source: "default-node22" },
    },
  ] satisfies Array<{
    name: string;
    env?: NodeJS.ProcessEnv;
    network?: TelegramNetworkConfig | (TelegramNetworkConfig & { dnsResultOrder: string });
    nodeMajor: number;
    expected: ReturnType<typeof resolveTelegramDnsResultOrderDecision>;
  }>)("$name", ({ env, network, nodeMajor, expected }) => {
    const decision = resolveTelegramDnsResultOrderDecision({
      env,
      network,
      nodeMajor,
    });
    expect(decision).toEqual(expected);
  });

  it("defaults to ipv4first on Node 22", () => {
    const decision = resolveTelegramDnsResultOrderDecision({ nodeMajor: 22 });
    expect(decision).toEqual({ value: "ipv4first", source: "default-node22" });
  });

  it("returns null when no dns decision applies", () => {
    const decision = resolveTelegramDnsResultOrderDecision({ nodeMajor: 20 });
    expect(decision).toEqual({ value: null });
  });
});
