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

let tempDir: string;

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

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

describe('getConfigPath', () => {
  it('returns path within config dir', () => {
    const path = getConfigPath('/tmp/mcpctl');
    expect(path).toBe('/tmp/mcpctl/config.json');
  });
});

describe('loadConfig', () => {
  it('returns defaults when no config file exists', () => {
    const config = loadConfig({ configDir: tempDir });
    expect(config).toEqual(DEFAULT_CONFIG);
  });

  it('loads config from file', () => {
    saveConfig({ ...DEFAULT_CONFIG, mcplocalUrl: 'http://custom:5000' }, { configDir: tempDir });
    const config = loadConfig({ configDir: tempDir });
    expect(config.mcplocalUrl).toBe('http://custom:5000');
  });

  it('applies defaults for missing fields', () => {
    const { writeFileSync } = require('node:fs') as typeof import('node:fs');
    writeFileSync(join(tempDir, 'config.json'), '{"mcplocalUrl":"http://x:1"}');
    const config = loadConfig({ configDir: tempDir });
    expect(config.mcplocalUrl).toBe('http://x:1');
    expect(config.registries).toEqual(['official', 'glama', 'smithery']);
  });

  it('backward compat: daemonUrl maps to mcplocalUrl', () => {
    const { writeFileSync } = require('node:fs') as typeof import('node:fs');
    writeFileSync(join(tempDir, 'config.json'), '{"daemonUrl":"http://old:3000"}');
    const config = loadConfig({ configDir: tempDir });
    expect(config.mcplocalUrl).toBe('http://old:3000');
  });
});

describe('saveConfig', () => {
  it('creates config file', () => {
    saveConfig(DEFAULT_CONFIG, { configDir: tempDir });
    expect(existsSync(join(tempDir, 'config.json'))).toBe(true);
  });

  it('creates config directory if missing', () => {
    const nested = join(tempDir, 'nested', 'dir');
    saveConfig(DEFAULT_CONFIG, { configDir: nested });
    expect(existsSync(join(nested, 'config.json'))).toBe(true);
  });

  it('round-trips configuration', () => {
    const custom = {
      ...DEFAULT_CONFIG,
      mcplocalUrl: 'http://custom:9000',
      registries: ['official' as const],
      outputFormat: 'json' as const,
    };
    saveConfig(custom, { configDir: tempDir });
    const loaded = loadConfig({ configDir: tempDir });
    expect(loaded).toEqual(custom);
  });
});

describe('mergeConfig', () => {
  it('merges overrides into existing config', () => {
    saveConfig(DEFAULT_CONFIG, { configDir: tempDir });
    const merged = mergeConfig({ mcplocalUrl: 'http://new:1234' }, { configDir: tempDir });
    expect(merged.mcplocalUrl).toBe('http://new:1234');
    expect(merged.registries).toEqual(DEFAULT_CONFIG.registries);
  });

  it('works when no config file exists', () => {
    const merged = mergeConfig({ outputFormat: 'yaml' }, { configDir: tempDir });
    expect(merged.outputFormat).toBe('yaml');
    expect(merged.mcplocalUrl).toBe('http://localhost:3200');
  });
});
