import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { mkdtempSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { createConfigCommand } from '../../src/commands/config.js';
import { loadConfig, saveConfig, DEFAULT_CONFIG } from '../../src/config/index.js';

let tempDir: string;
let output: string[];

function log(...args: string[]) {
  output.push(args.join(' '));
}

beforeEach(() => {
  tempDir = mkdtempSync(join(tmpdir(), 'mcpctl-config-test-'));
  output = [];
});

afterEach(() => {
  rmSync(tempDir, { recursive: true, force: true });
});

function makeCommand() {
  return createConfigCommand({
    configDeps: { configDir: tempDir },
    log,
  });
}

describe('config view', () => {
  it('outputs default config as JSON', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['view'], { from: 'user' });
    expect(output).toHaveLength(1);
    const parsed = JSON.parse(output[0]) as Record<string, unknown>;
    expect(parsed['mcplocalUrl']).toBe('http://localhost:3200');
    expect(parsed['mcpdUrl']).toBe('http://localhost:3100');
  });

  it('outputs config as YAML with --output yaml', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['view', '-o', 'yaml'], { from: 'user' });
    expect(output[0]).toContain('mcplocalUrl:');
  });
});

describe('config set', () => {
  it('sets mcplocalUrl', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['set', 'mcplocalUrl', 'http://new:9000'], { from: 'user' });
    expect(output[0]).toContain('mcplocalUrl');
    const config = loadConfig({ configDir: tempDir });
    expect(config.mcplocalUrl).toBe('http://new:9000');
  });

  it('sets mcpdUrl', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['set', 'mcpdUrl', 'http://remote:3100'], { from: 'user' });
    const config = loadConfig({ configDir: tempDir });
    expect(config.mcpdUrl).toBe('http://remote:3100');
  });

  it('maps daemonUrl to mcplocalUrl for backward compat', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['set', 'daemonUrl', 'http://legacy:3000'], { from: 'user' });
    const config = loadConfig({ configDir: tempDir });
    expect(config.mcplocalUrl).toBe('http://legacy:3000');
  });

  it('sets cacheTTLMs as integer', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['set', 'cacheTTLMs', '60000'], { from: 'user' });
    const config = loadConfig({ configDir: tempDir });
    expect(config.cacheTTLMs).toBe(60000);
  });

  it('sets registries as comma-separated list', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['set', 'registries', 'official,glama'], { from: 'user' });
    const config = loadConfig({ configDir: tempDir });
    expect(config.registries).toEqual(['official', 'glama']);
  });

  it('sets outputFormat', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['set', 'outputFormat', 'json'], { from: 'user' });
    const config = loadConfig({ configDir: tempDir });
    expect(config.outputFormat).toBe('json');
  });
});

describe('config path', () => {
  it('shows config file path', async () => {
    const cmd = makeCommand();
    await cmd.parseAsync(['path'], { from: 'user' });
    expect(output[0]).toContain(tempDir);
    expect(output[0]).toContain('config.json');
  });
});

describe('config reset', () => {
  it('resets to defaults', async () => {
    // First set a custom value
    saveConfig({ ...DEFAULT_CONFIG, mcplocalUrl: 'http://custom' }, { configDir: tempDir });

    const cmd = makeCommand();
    await cmd.parseAsync(['reset'], { from: 'user' });
    expect(output[0]).toContain('reset');

    const config = loadConfig({ configDir: tempDir });
    expect(config.mcplocalUrl).toBe(DEFAULT_CONFIG.mcplocalUrl);
  });
});
