import test from 'node:test';
import assert from 'node:assert/strict';

import type { Bug } from './bug';
import { calcXiaobaoVersionRisk } from './xiaobao-risk';
import { buildRiskSignature, findLatestDailySnapshot, shouldSaveRiskSnapshot, summarizeRiskTrend } from './xiaobao-risk-trend';
import type { XiaobaoRiskSnapshot } from './xiaobao-risk-trend';

function snapshot(patch: Partial<XiaobaoRiskSnapshot>): XiaobaoRiskSnapshot {
  return {
    versionId: 'ver-1',
    date: '2026-06-27',
    riskScore: 38,
    riskLevel: 'attention',
    openBugCount: 0,
    failedTestCount: 0,
    blockedCount: 0,
    silentRiskCount: 0,
    confidence: 80,
    createdAt: '2026-06-27T01:00:00.000Z',
    ...patch,
  };
}

test('summarizeRiskTrend detects continuous rising risk across three snapshots', () => {
  const trend = summarizeRiskTrend([
    snapshot({ riskScore: 71, createdAt: '2026-06-29T01:00:00.000Z', date: '2026-06-29' }),
    snapshot({ riskScore: 38, createdAt: '2026-06-27T01:00:00.000Z', date: '2026-06-27' }),
    snapshot({ riskScore: 52, createdAt: '2026-06-28T01:00:00.000Z', date: '2026-06-28' }),
  ]);

  assert.equal(trend.direction, 'up');
  assert.equal(trend.delta, 33);
  assert.equal(trend.pattern, 'continuous_rising');
});

test('buildRiskSignature changes when score and bug counts change', () => {
  const base = buildRiskSignature(snapshot({ riskScore: 52, openBugCount: 1 }));
  const changed = buildRiskSignature(snapshot({ riskScore: 71, openBugCount: 2 }));

  assert.notEqual(base, changed);
});

test('buildRiskSignature changes when critical bug count changes without open bug count change', () => {
  const base = buildRiskSignature(snapshot({ openBugCount: 2, criticalBugCount: 0 }));
  const changed = buildRiskSignature(snapshot({ openBugCount: 2, criticalBugCount: 1 }));

  assert.notEqual(base, changed);
});

test('buildRiskSignature ignores volatile same-day forecast time shifts', () => {
  const base = snapshot({
    forecastReleaseDate: '2026-07-15T06:30:00.000Z',
    createdAt: '2026-06-30T08:00:00.000Z',
  });
  const changed = snapshot({
    forecastReleaseDate: '2026-07-15T09:46:04.706Z',
    createdAt: '2026-06-30T08:16:04.720Z',
  });

  assert.equal(buildRiskSignature(changed), buildRiskSignature(base));
  assert.equal(shouldSaveRiskSnapshot(changed, base, new Date('2026-06-30T08:16:04.720Z')), false);
});

test('findLatestDailySnapshot returns latest same-day snapshot for a version', () => {
  const latest = findLatestDailySnapshot([
    snapshot({ versionId: 'ver-1', date: '2026-06-29', riskScore: 40, createdAt: '2026-06-29T09:00:00.000Z' }),
    snapshot({ versionId: 'ver-1', date: '2026-06-29', riskScore: 45, createdAt: '2026-06-29T10:00:00.000Z' }),
    snapshot({ versionId: 'ver-1', date: '2026-06-28', riskScore: 70, createdAt: '2026-06-28T10:00:00.000Z' }),
    snapshot({ versionId: 'ver-2', date: '2026-06-29', riskScore: 90, createdAt: '2026-06-29T11:00:00.000Z' }),
  ], 'ver-1', '2026-06-29');

  assert.equal(latest?.riskScore, 45);
});

test('shouldSaveRiskSnapshot skips small same-day changes inside throttle window', () => {
  const previous = snapshot({ date: '2026-06-29', riskScore: 40, createdAt: '2026-06-29T10:00:00.000Z' });
  const current = snapshot({ date: '2026-06-29', riskScore: 43, createdAt: '2026-06-29T10:03:00.000Z' });

  assert.equal(shouldSaveRiskSnapshot(current, previous, new Date('2026-06-29T10:03:00.000Z')), false);
});

test('shouldSaveRiskSnapshot saves material signal changes immediately', () => {
  const previous = snapshot({ date: '2026-06-29', riskScore: 40, criticalBugCount: 0, createdAt: '2026-06-29T10:00:00.000Z' });
  const current = snapshot({ date: '2026-06-29', riskScore: 41, criticalBugCount: 1, createdAt: '2026-06-29T10:02:00.000Z' });

  assert.equal(shouldSaveRiskSnapshot(current, previous, new Date('2026-06-29T10:02:00.000Z')), true);
});

test('shouldSaveRiskSnapshot saves minor signature changes after throttle window', () => {
  const previous = snapshot({ date: '2026-06-29', riskScore: 40, createdAt: '2026-06-29T10:00:00.000Z' });
  const current = snapshot({ date: '2026-06-29', riskScore: 43, createdAt: '2026-06-29T10:12:00.000Z' });

  assert.equal(shouldSaveRiskSnapshot(current, previous, new Date('2026-06-29T10:12:00.000Z')), true);
});

test('calcXiaobaoVersionRisk uses all open bugs in the current trend snapshot signature', () => {
  const now = new Date('2026-07-02T01:00:00.000Z');
  const risk = calcXiaobaoVersionRisk({
    version: {
      id: 'ver-1',
      name: 'V1.0',
      expectedReleaseDate: '2026-07-03T10:00:00.000Z',
      members: [{ name: 'Alice' }],
    },
    devTasks: [],
    testCases: [],
    bugs: [bug({ severity: 'major', priority: 'P2' })],
    now,
  });
  const currentSignature = (risk.trend as { currentSignature?: string }).currentSignature;

  assert.equal(risk.signals.openBugCount, 1);
  assert.equal(risk.signals.criticalBugCount, 0);
  assert.equal(risk.currentSnapshot.openBugCount, 1);
  assert.equal(risk.currentSnapshot.criticalBugCount, 0);
  assert.equal(currentSignature, buildRiskSignature(risk.currentSnapshot));
  assert.equal(buildRiskSignature(risk.currentSnapshot).split('|')[5], '1');
});

function bug(patch: Partial<Bug> = {}): Bug {
  return {
    id: 'bug-1',
    bugNo: 'BUG-001',
    versionId: 'ver-1',
    testCaseId: 'tc-1',
    title: 'Non-critical open bug',
    description: 'Open but not critical.',
    severity: 'major',
    priority: 'P2',
    reportedBy: 'qa-1',
    assigneeId: 'dev-1',
    status: 'open',
    createdAt: '2026-07-01T09:00:00.000Z',
    updatedAt: '2026-07-01T09:00:00.000Z',
    ...patch,
  };
}
