import { describe, it, expect } from 'vitest';
import { splitCategories, buildPolicyPatch, countEnabledCategories } from './toolPolicy';
import type { ToolCategory } from '../api';

const cats: ToolCategory[] = [
  { name: 'core', sensitive: false, enabled: true },
  { name: 'web', sensitive: false, enabled: true },
  { name: 'office', sensitive: false, enabled: false },
  { name: 'ssh', sensitive: true, enabled: false },
  { name: 'browser', sensitive: true, enabled: true },
];

describe('splitCategories', () => {
  it('splits by sensitive flag', () => {
    const { safe, sensitive } = splitCategories(cats);
    expect(safe.map(c => c.name)).toEqual(['core', 'web', 'office']);
    expect(sensitive.map(c => c.name)).toEqual(['ssh', 'browser']);
  });

  it('returns empty arrays when input is empty', () => {
    const { safe, sensitive } = splitCategories([]);
    expect(safe).toEqual([]);
    expect(sensitive).toEqual([]);
  });
});

describe('buildPolicyPatch', () => {
  it('respects category default enabled state when no overrides', () => {
    const patch = buildPolicyPatch(cats, {}, {});
    // 'office' is safe + disabled by default → disabledSafe
    expect(patch.disabledSafe).toEqual(['office']);
    // 'browser' is sensitive + enabled by default → enabledSensitive
    expect(patch.enabledSensitive).toEqual(['browser']);
  });

  it('override toggledSafe disables a previously-enabled category', () => {
    const patch = buildPolicyPatch(cats, { core: false }, {});
    expect(patch.disabledSafe).toContain('core');
    expect(patch.disabledSafe).toContain('office');
  });

  it('override toggledSafe re-enables a previously-disabled category', () => {
    const patch = buildPolicyPatch(cats, { office: true }, {});
    expect(patch.disabledSafe).not.toContain('office');
  });

  it('override toggledSens opts in a sensitive category', () => {
    const patch = buildPolicyPatch(cats, {}, { ssh: true });
    expect(patch.enabledSensitive).toContain('ssh');
    expect(patch.enabledSensitive).toContain('browser');
  });

  it('override toggledSens opts out a sensitive category', () => {
    const patch = buildPolicyPatch(cats, {}, { browser: false });
    expect(patch.enabledSensitive).not.toContain('browser');
  });

  // 個別センシティブツール（Bash 等）は categories ではなく sensitiveTools 配列で
  // 配信される。buildPolicyPatch がこれを走査しないと、トグル ON にしても
  // enabledSensitive に載らず保存が落ちる（実機で再現したバグ）。
  const sensTools = [{ name: 'Bash', enabled: false }];

  it('omits a default-off sensitive tool when not toggled', () => {
    const patch = buildPolicyPatch(cats, {}, {}, sensTools);
    expect(patch.enabledSensitive).not.toContain('Bash');
  });

  it('includes a sensitive tool (Bash) when toggled on', () => {
    const patch = buildPolicyPatch(cats, {}, { Bash: true }, sensTools);
    expect(patch.enabledSensitive).toContain('Bash');
    // センシティブカテゴリのデフォルト ON も同時に維持される
    expect(patch.enabledSensitive).toContain('browser');
  });

  it('preserves an already-enabled sensitive tool when not toggled', () => {
    const patch = buildPolicyPatch(cats, {}, {}, [{ name: 'Bash', enabled: true }]);
    expect(patch.enabledSensitive).toContain('Bash');
  });

  it('drops an enabled sensitive tool when toggled off', () => {
    const patch = buildPolicyPatch(cats, {}, { Bash: false }, [{ name: 'Bash', enabled: true }]);
    expect(patch.enabledSensitive).not.toContain('Bash');
  });

  it('does not duplicate a name shared by a category and a tool toggle', () => {
    // 同名衝突しても enabledSensitive は一意であること
    const patch = buildPolicyPatch(cats, {}, { ssh: true }, [{ name: 'ssh', enabled: true }]);
    expect(patch.enabledSensitive.filter(n => n === 'ssh')).toHaveLength(1);
  });
});

describe('countEnabledCategories', () => {
  it('counts enabled categories with defaults', () => {
    // core(on), web(on), office(off), ssh(off), browser(on) → 3
    expect(countEnabledCategories(cats, {}, {})).toBe(3);
  });

  it('reflects toggle overrides', () => {
    // disable core (−1), enable office (+1), enable ssh (+1) → 4
    expect(countEnabledCategories(cats, { core: false, office: true }, { ssh: true })).toBe(4);
  });
});
