import { describe, expect, it } from 'vitest';
import { normalizePieceConfig, mergeProviderOptions } from '../infra/config/loaders/pieceParser.js';

describe('normalizePieceConfig provider_options', () => {
  it('piece-level global を movement に継承し、movement 側で上書きできる', () => {
    const raw = {
      name: 'provider-options',
      piece_config: {
        provider_options: {
          codex: { network_access: true },
          opencode: { network_access: false },
        },
      },
      movements: [
        {
          name: 'codex-default',
          provider: 'codex',
          instruction: '{task}',
        },
        {
          name: 'codex-override',
          provider: 'codex',
          provider_options: {
            codex: { network_access: false },
          },
          instruction: '{task}',
        },
      ],
    };

    const config = normalizePieceConfig(raw, process.cwd());

    expect(config.providerOptions).toEqual({
      codex: { networkAccess: true },
      opencode: { networkAccess: false },
    });
    expect(config.movements[0]?.providerOptions).toEqual({
      codex: { networkAccess: true },
      opencode: { networkAccess: false },
    });
    expect(config.movements[1]?.providerOptions).toEqual({
      codex: { networkAccess: false },
      opencode: { networkAccess: false },
    });
  });

  it('claude sandbox を piece-level で設定し movement で上書きできる', () => {
    const raw = {
      name: 'claude-sandbox',
      piece_config: {
        provider_options: {
          claude: {
            sandbox: { allow_unsandboxed_commands: true },
          },
        },
      },
      movements: [
        {
          name: 'inherit',
          instruction: '{task}',
        },
        {
          name: 'override',
          provider_options: {
            claude: {
              sandbox: {
                allow_unsandboxed_commands: false,
                excluded_commands: ['./gradlew'],
              },
            },
          },
          instruction: '{task}',
        },
      ],
    };

    const config = normalizePieceConfig(raw, process.cwd());

    expect(config.providerOptions).toEqual({
      claude: { sandbox: { allowUnsandboxedCommands: true } },
    });
    expect(config.movements[0]?.providerOptions).toEqual({
      claude: { sandbox: { allowUnsandboxedCommands: true } },
    });
    expect(config.movements[1]?.providerOptions).toEqual({
      claude: {
        sandbox: {
          allowUnsandboxedCommands: false,
          excludedCommands: ['./gradlew'],
        },
      },
    });
  });

  it('piece-level runtime.prepare を正規化し重複を除去する', () => {
    const raw = {
      name: 'runtime-prepare',
      piece_config: {
        runtime: {
          prepare: ['gradle', 'node', 'gradle'],
        },
      },
      movements: [
        {
          name: 'implement',
          instruction: '{task}',
        },
      ],
    };

    const config = normalizePieceConfig(raw, process.cwd());

    expect(config.runtime).toEqual({
      prepare: ['gradle', 'node'],
    });
  });
});

describe('mergeProviderOptions', () => {
  it('複数層を正しくマージする（後の層が優先）', () => {
    const global = {
      claude: { sandbox: { allowUnsandboxedCommands: false, excludedCommands: ['./gradlew'] } },
      codex: { networkAccess: true },
    };
    const local = {
      claude: { sandbox: { allowUnsandboxedCommands: true } },
    };
    const step = {
      codex: { networkAccess: false },
    };

    const result = mergeProviderOptions(global, local, step);

    expect(result).toEqual({
      claude: { sandbox: { allowUnsandboxedCommands: true, excludedCommands: ['./gradlew'] } },
      codex: { networkAccess: false },
    });
  });

  it('すべて undefined なら undefined を返す', () => {
    expect(mergeProviderOptions(undefined, undefined, undefined)).toBeUndefined();
  });
});
