import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { handleGetConfig, handlePutScopedConfig } from '@myco/daemon/api/config';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import YAML from 'yaml';

describe('config API', () => {
  let vaultDir: string;

  beforeEach(() => {
    vaultDir = fs.mkdtempSync(path.join(os.tmpdir(), 'myco-api-'));
    const config = { version: 3, embedding: { provider: 'ollama', model: 'bge-m3' } };
    fs.writeFileSync(path.join(vaultDir, 'myco.yaml'), YAML.stringify(config));
  });

  afterEach(() => {
    fs.rmSync(vaultDir, { recursive: true, force: true });
  });

  it('GET returns parsed config', async () => {
    const result = await handleGetConfig(vaultDir);
    expect(result.body).toHaveProperty('version', 3);
  });

  it('PUT scoped patch merges and saves config', async () => {
    // capture.* moved to Machine tier (2026-06 scope correction), so a project
    // scoped PUT now uses a project-tier field (release_provenance.*).
    const result = await handlePutScopedConfig(vaultDir, {
      scope: 'project',
      patch: {
        release_provenance: { production_debug_include_unknown: false },
      },
    });
    expect(result.status).toBeUndefined(); // 200 default
    const saved = YAML.parse(fs.readFileSync(path.join(vaultDir, 'myco.yaml'), 'utf-8')) as {
      release_provenance?: { production_debug_include_unknown?: boolean };
    };
    expect(saved.release_provenance?.production_debug_include_unknown).toBe(false);
  });

  it('PUT scoped patch preserves unrelated sections', async () => {
    // Patch a project-tier field; verify previously-saved fields stay
    // intact. (Machine-tier fields like `daemon.log_level`, `capture.*`,
    // `notifications.*` are silently dropped from the project file by
    // ProjectConfigSchema — that's covered separately in tier-dispatch tests.)
    await handlePutScopedConfig(vaultDir, {
      scope: 'project',
      patch: { release_provenance: { production_debug_include_unknown: false } },
    });
    const saved = YAML.parse(fs.readFileSync(path.join(vaultDir, 'myco.yaml'), 'utf-8')) as {
      release_provenance?: { production_debug_include_unknown?: boolean };
    };
    expect(saved.release_provenance?.production_debug_include_unknown).toBe(false);
    // Verify another project-tier section is preserved
    const merged = YAML.parse(fs.readFileSync(path.join(vaultDir, 'myco.yaml'), 'utf-8'));
    expect(merged.version).toBe(3);
  });

  it('PUT scoped returns 400 for missing patch', async () => {
    const result = await handlePutScopedConfig(vaultDir, { scope: 'project' });
    expect(result.status).toBe(400);
  });

  it('PUT scoped returns 400 for schema-invalid patch', async () => {
    const result = await handlePutScopedConfig(vaultDir, {
      scope: 'project',
      patch: { embedding: { provider: 'invalid-provider' } },
    });
    expect(result.status).toBe(400);
  });
});
