/**
 * Shared test fixtures for `test/unit/group/*` test files. Keep this small
 * and purpose-built — it's NOT a general-purpose factory. If a builder here
 * grows complex enough to need its own module, move it next to the code
 * under test (e.g. `bridge-db.fixtures.ts`) instead of ballooning this file.
 */

import fsp from 'node:fs/promises';
import path from 'node:path';
import { vi } from 'vitest';
import type { GroupToolPort } from '../../../src/core/group/service.js';
import type { StoredContract } from '../../../src/core/group/types.js';

/**
 * Canonical baseline contract used by bridge-db and related tests. Every
 * field is populated so callers get a valid `StoredContract` with zero args,
 * and any field can be overridden via the partial — e.g.
 * `makeContract({ role: 'consumer', repo: 'frontend' })`.
 *
 * Prefer passing a `Partial<StoredContract>` override for the specific
 * field you care about rather than mutating the returned object in place.
 */
export function makeContract(overrides: Partial<StoredContract> = {}): StoredContract {
  return {
    contractId: 'http::GET::/api/users',
    type: 'http',
    role: 'provider',
    symbolUid: 'uid-1',
    symbolRef: { filePath: 'src/routes.ts', name: 'getUsers' },
    symbolName: 'getUsers',
    confidence: 0.85,
    meta: {},
    repo: 'backend',
    ...overrides,
  };
}

/**
 * Write the `waveful` group's `group.yaml` into `groupDir` (creating it), with
 * every detector disabled so a suite's own bridge rows are the only thing that
 * can produce a crossing.
 *
 * Each entry of `repos` is a member name; its registry entry is
 * `<name>-registry`, which is the name `resolveRepo` is called with — several
 * suites assert on exactly that string.
 */
export async function writeGroupYaml(groupDir: string, repos: string[]): Promise<void> {
  await fsp.mkdir(groupDir, { recursive: true });
  const repoLines = repos.map((name) => `  ${name}: ${name}-registry`).join('\n');
  await fsp.writeFile(
    path.join(groupDir, 'group.yaml'),
    `version: 1
name: waveful
description: ""
repos:
${repoLines}
links: []
packages: {}
detect:
  http: false
  grpc: false
  thrift: false
  topics: false
  shared_libs: false
  embedding_fallback: false
matching:
  bm25_threshold: 0.7
  embedding_threshold: 0.65
  max_candidates_per_step: 3
`,
    'utf8',
  );
}

/**
 * A `GroupToolPort` whose legs are all benign stubs: every repo resolves under
 * `home`, the local impact walk reports one direct dependent, and a fanned-out
 * neighbour comes back with nothing.
 *
 * Pass `overrides` for the ONE leg a test is about — making it throw, hang, or
 * return a shaped result — so the difference under test is the only difference
 * in the port. Note that `vi.mock` factories cannot move here: vitest hoists
 * them per test module, so each suite keeps its own `bridge-db` mock.
 */
export function makeGroupToolPort(
  home: string,
  overrides: Partial<GroupToolPort> = {},
): GroupToolPort {
  return {
    resolveRepo: vi.fn(async (name: string) => ({
      id: name,
      name,
      repoPath: name,
      storagePath: path.join(home, name),
    })),
    impact: vi.fn(async () => ({
      target: { id: 'Function:src/api.ts:publish', filePath: 'src/api.ts' },
      byDepth: {},
      summary: { direct: 1, processes_affected: 0, modules_affected: 0 },
      risk: 'LOW',
    })),
    impactByUid: vi.fn(async () => ({
      byDepth: {},
      summary: { direct: 0, processes_affected: 0, modules_affected: 0 },
      risk: 'LOW',
    })),
    query: vi.fn(),
    context: vi.fn(),
    ...overrides,
  } as GroupToolPort;
}
