import { describe, it, expect } from 'vitest';
import { existsSync, readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';

// Codex P2 #7: the setup wizard server shares its pure LLM logic with the CLI
// via scripts/setup-lib.mjs, imported at RUNTIME by the relative specifier
// `../../scripts/setup-lib.mjs`. Both the dev (src/bridge) and built
// (dist/bridge) modules sit two levels under the repo root, so that specifier
// resolves to <root>/scripts/setup-lib.mjs in either layout. If the file goes
// missing from the runtime image (e.g. the Dockerfile stops copying it), the
// setup endpoints 500 on first boot. These tests fix that contract.

const here = dirname(fileURLToPath(import.meta.url)); // .../src/bridge
const repoRoot = resolve(here, '../..');

describe('setup-lib distribution resolution (P2 #7)', () => {
  it('the shared .mjs exists at <root>/scripts and is reachable via ../../scripts from bridge', () => {
    // src/bridge and dist/bridge both resolve `../../scripts` to <root>/scripts.
    const fromBridge = resolve(here, '../../scripts/setup-lib.mjs');
    expect(fromBridge).toBe(resolve(repoRoot, 'scripts/setup-lib.mjs'));
    expect(existsSync(fromBridge)).toBe(true);
  });

  it('importing the runtime specifier yields the exports setup-api depends on', async () => {
    const lib = await import('../../scripts/setup-lib.mjs');
    for (const name of ['isLlmConfigured', 'parseEndpoint', 'probeModels', 'buildLlmWorkerCamel', 'CONNECTION_TYPES']) {
      expect(lib[name as keyof typeof lib], `missing export ${name}`).toBeDefined();
    }
  });

  it('the Dockerfile runtime stage copies the shared .mjs into the image', () => {
    const dockerfile = readFileSync(resolve(repoRoot, 'Dockerfile'), 'utf8');
    // Must appear AFTER the second FROM (runtime stage), not only in the builder.
    const stages = dockerfile.split(/^FROM /m);
    const runtimeStage = stages[stages.length - 1];
    expect(runtimeStage).toMatch(/COPY\s+scripts\/setup-lib\.mjs\s+\.\/scripts\/setup-lib\.mjs/);
  });

  it('the Dockerfile ships an UNCONFIGURED default config.yaml so a fresh install shows the wizard', () => {
    const dockerfile = readFileSync(resolve(repoRoot, 'Dockerfile'), 'utf8');
    // Baking the fully-worked example as the live config (it has an enabled
    // localhost worker) would mark a fresh install "configured" and suppress
    // the wizard. The image must instead write a minimal config_version:2 file.
    expect(dockerfile).not.toMatch(/COPY\s+config\.yaml\.example\s+\.\/config\.yaml\s*$/m);
    expect(dockerfile).toMatch(/config_version:\s*2[^\n]*>\s*\.\/config\.yaml/);
  });

  it('the shipped example IS configured (guards the test above from going stale)', () => {
    // Sanity: confirm config.yaml.example really does carry a usable worker, so
    // the "ship a minimal default instead" fix is actually load-bearing.
    const example = readFileSync(resolve(repoRoot, 'config.yaml.example'), 'utf8');
    expect(example).toMatch(/^\s*model:\s*\S+/m);
    expect(example).toMatch(/^\s*endpoint:\s*\S+/m);
  });
});
