import { createHash } from 'crypto';
import * as fs from 'fs/promises';
import * as os from 'os';
import * as path from 'path';
import { afterEach, describe, expect, it } from 'vitest';

import {
  getTeamsBasePath,
  setClaudeBasePathOverride,
} from '../../../../../src/main/utils/pathDecoder';
import { TeamTaskLogFreshnessReader } from '../../../../../src/main/services/team/stallMonitor/TeamTaskLogFreshnessReader';

const tempDirs: string[] = [];

function safeTaskIdSegment(taskId: string): string {
  return `task-id-${createHash('sha256').update(taskId).digest('hex').slice(0, 32)}`;
}

afterEach(async () => {
  setClaudeBasePathOverride(null);
  await Promise.all(
    tempDirs.splice(0).map(async (dirPath) => {
      await fs.rm(dirPath, { recursive: true, force: true });
    })
  );
});

function teamSignalDir(teamName: string): string {
  return path.join(getTeamsBasePath(), teamName, 'task-log-freshness');
}

describe('TeamTaskLogFreshnessReader', () => {
  it('reads valid freshness signals and normalizes transcript basename', async () => {
    const projectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'stall-freshness-'));
    tempDirs.push(projectDir);
    const signalDir = path.join(projectDir, '.board-task-log-freshness');
    await fs.mkdir(signalDir, { recursive: true });

    await fs.writeFile(
      path.join(signalDir, `${encodeURIComponent('task-a')}.json`),
      JSON.stringify({
        taskId: 'task-a',
        updatedAt: '2026-04-19T12:00:00.000Z',
        transcriptFile: '/tmp/nested/session-a.jsonl',
      }),
      'utf8'
    );
    await fs.writeFile(
      path.join(signalDir, `${encodeURIComponent('task-b')}.json`),
      JSON.stringify({
        taskId: 'task-b',
        updatedAt: 'not-a-date',
      }),
      'utf8'
    );

    const signals = await new TeamTaskLogFreshnessReader().readSignals(projectDir, [
      'task-a',
      'task-b',
      'task-missing',
    ]);

    expect([...signals.keys()]).toEqual(['task-a']);
    expect(signals.get('task-a')).toEqual({
      taskId: 'task-a',
      updatedAt: '2026-04-19T12:00:00.000Z',
      filePath: path.join(signalDir, `${encodeURIComponent('task-a')}.json`),
      transcriptFileBasename: 'session-a.jsonl',
    });
  });

  it('reads Windows-safe hashed freshness files for reserved task ids', async () => {
    const projectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'stall-freshness-'));
    tempDirs.push(projectDir);
    const signalDir = path.join(projectDir, '.board-task-log-freshness');
    await fs.mkdir(signalDir, { recursive: true });

    await fs.writeFile(
      path.join(signalDir, `${safeTaskIdSegment('CON')}.json`),
      JSON.stringify({
        taskId: 'CON',
        updatedAt: '2026-04-19T12:00:00.000Z',
        transcriptFile: 'session-con.jsonl',
      }),
      'utf8'
    );

    const signals = await new TeamTaskLogFreshnessReader().readSignals(projectDir, ['CON']);

    expect(signals.get('CON')?.filePath).toBe(
      path.join(signalDir, `${safeTaskIdSegment('CON')}.json`)
    );
    expect(signals.get('CON')?.transcriptFileBasename).toBe('session-con.jsonl');
  });

  it('prefers team-scoped freshness signals', async () => {
    const projectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'stall-freshness-'));
    tempDirs.push(projectDir);
    setClaudeBasePathOverride(path.join(projectDir, '.claude'));
    const signalDir = teamSignalDir('demo');
    await fs.mkdir(signalDir, { recursive: true });

    await fs.writeFile(
      path.join(signalDir, `${encodeURIComponent('task-a')}.json`),
      JSON.stringify({
        taskId: 'task-a',
        updatedAt: '2026-04-19T12:00:00.000Z',
      }),
      'utf8'
    );

    const signals = await new TeamTaskLogFreshnessReader().readSignals(projectDir, ['task-a'], {
      teamName: 'demo',
    });

    expect(signals.get('task-a')?.filePath).toBe(
      path.join(signalDir, `${encodeURIComponent('task-a')}.json`)
    );
  });

  it('reads hashed freshness files for very long task ids', async () => {
    const projectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'stall-freshness-'));
    tempDirs.push(projectDir);
    const signalDir = path.join(projectDir, '.board-task-log-freshness');
    await fs.mkdir(signalDir, { recursive: true });
    const taskId = `task-${'x'.repeat(180)}`;

    await fs.writeFile(
      path.join(signalDir, `${safeTaskIdSegment(taskId)}.json`),
      JSON.stringify({
        taskId,
        updatedAt: '2026-04-19T12:00:00.000Z',
        transcriptFile: 'session-long.jsonl',
      }),
      'utf8'
    );

    const signals = await new TeamTaskLogFreshnessReader().readSignals(projectDir, [taskId]);

    expect(signals.get(taskId)?.filePath).toBe(
      path.join(signalDir, `${safeTaskIdSegment(taskId)}.json`)
    );
    expect(signals.get(taskId)?.transcriptFileBasename).toBe('session-long.jsonl');
  });
});
