import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';

import { vi } from 'vitest';

describe('main Sentry telemetry gate', () => {
  let previousDsn: string | undefined;

  beforeEach(() => {
    previousDsn = process.env.SENTRY_DSN;
    process.env.SENTRY_DSN = 'https://public@example.com/1';
    vi.resetModules();
  });

  afterEach(() => {
    if (previousDsn === undefined) {
      delete process.env.SENTRY_DSN;
    } else {
      process.env.SENTRY_DSN = previousDsn;
    }
    vi.resetModules();
  });

  it('does not initialize Sentry when persisted telemetry config is disabled', async () => {
    const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-teams-sentry-config-'));
    fs.writeFileSync(
      path.join(tempRoot, 'agent-teams-config.json'),
      JSON.stringify({ general: { telemetryEnabled: false } }),
      'utf8'
    );

    const { setClaudeBasePathOverride } = await import('@main/utils/pathDecoder');
    setClaudeBasePathOverride(tempRoot);

    const sentrySdk = await import('@sentry/electron/main');
    const init = vi.mocked(sentrySdk.init);
    init.mockClear();

    const sentry = await import('@main/sentry');

    expect(sentry.readPersistedTelemetryEnabled(tempRoot)).toBe(false);
    expect(init).not.toHaveBeenCalled();
    expect(sentry.filterSentryEventForTelemetry({ ok: true })).toBeNull();

    setClaudeBasePathOverride(null);
    fs.rmSync(tempRoot, { recursive: true, force: true });
  });

  it('clears user scope and drops events when telemetry is disabled', async () => {
    const sentry = await import('@main/sentry');
    const sentryApi = {
      setUser: vi.fn(),
      setTags: vi.fn(),
      close: vi.fn(() => Promise.resolve(true)),
    };
    sentry.setMainSentryApiForTesting(sentryApi);

    sentry.syncTelemetryFlag(false);

    expect(sentryApi.setUser).toHaveBeenCalledWith(null);
    expect(sentryApi.close).toHaveBeenCalled();
    expect(sentry.filterSentryEventForTelemetry({ ok: true })).toBeNull();
  });

  it('returns only hashed anonymous Sentry context when telemetry is enabled', async () => {
    const sentry = await import('@main/sentry');

    sentry.syncTelemetryFlag(true);
    const context = await sentry.getCurrentSentryTelemetryContext();

    expect(context?.userId).toMatch(/^[a-f0-9]{64}$/);
    expect(Object.keys(context?.tags ?? {}).sort((a, b) => a.localeCompare(b))).toEqual([
      'app_version',
      'arch',
      'identity_source',
      'platform',
    ]);
  });

  it('does not attach high-cardinality breadcrumb data', async () => {
    const sentry = await import('@main/sentry');
    const sentryApi = {
      addBreadcrumb: vi.fn(),
    };
    sentry.setMainSentryApiForTesting(sentryApi);

    sentry.addMainBreadcrumb('team', 'launch', { teamName: 'private-team-name' });

    expect(sentryApi.addBreadcrumb).toHaveBeenCalledWith({
      category: 'team',
      message: 'launch',
      level: 'info',
    });
  });

  it('redacts sensitive fields before allowing telemetry events', async () => {
    const sentry = await import('@main/sentry');

    sentry.syncTelemetryFlag(true);
    const filtered = sentry.filterSentryEventForTelemetry({
      message: 'Failed for user dev@example.com in /Users/alice/private-repo',
      extra: {
        projectPath: '/Users/alice/private-repo',
        token: 'sk-testsecretsecretsecret',
        accountUuid: 'd9b2d63a-582c-4d69-8a01-90e8199f532d',
      },
    });

    const serialized = JSON.stringify(filtered);
    expect(serialized).not.toContain('dev@example.com');
    expect(serialized).not.toContain('alice');
    expect(serialized).not.toContain('private-repo');
    expect(serialized).not.toContain('sk-testsecretsecretsecret');
    expect(serialized).not.toContain('d9b2d63a-582c-4d69-8a01-90e8199f532d');
  });

  it('only exposes safe low-cardinality telemetry tags', async () => {
    const { getSafeSentryTelemetryTags } = await import('@main/sentry');

    expect(
      Object.keys(getSafeSentryTelemetryTags('app-data')).sort((a, b) => a.localeCompare(b))
    ).toEqual(['app_version', 'arch', 'identity_source', 'platform']);
  });
});
