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

import type { Bug } from './bug';
import type { DevTask } from './dev-task';
import type { TestCase } from './test-case';
import type { TaskWorklog } from './task-worklog';
import type { VersionPlan } from './version-plan';
import type { WorkActivity } from './work-activity';
import { buildVersionDailyEvidence, buildXiaobaoWorkItems } from './xiaobao-risk-evidence';

function plan(patch: Partial<VersionPlan> = {}): VersionPlan {
  return {
    id: 'plan-1',
    versionId: 'ver-1',
    type: 'product',
    title: 'Product plan',
    owner: 'pm-1',
    startTime: '2026-06-20T01:00:00.000Z',
    endTime: '2026-06-25T10:00:00.000Z',
    status: 'in_progress',
    actualStartAt: '2026-06-20T01:00:00.000Z',
    createdAt: '2026-06-20T01:00:00.000Z',
    addedBy: 'pm-1',
    ...patch,
  };
}

function devTask(patch: Partial<DevTask> = {}): DevTask {
  return {
    id: 'dev-1',
    taskNo: 'DEV-001',
    requirementId: 'req-1',
    title: 'Build warning panel',
    categoryId: 'frontend',
    assigneeId: 'dev-other',
    priority: 'P1',
    expectedStartAt: '2026-06-20T01:00:00.000Z',
    expectedEndAt: '2026-06-26T10:00:00.000Z',
    status: 'in_progress',
    isBlocked: false,
    actualStartAt: '2026-06-20T01:00:00.000Z',
    createdBy: 'pm-1',
    createdAt: '2026-06-20T01:00:00.000Z',
    updatedAt: '2026-06-24T02:00:00.000Z',
    ...patch,
  };
}

function testCase(patch: Partial<TestCase> = {}): TestCase {
  return {
    id: 'tc-1',
    caseNo: 'TC-001',
    versionId: 'ver-1',
    title: 'Verify warning panel',
    categoryId: 'ui-interaction',
    priority: 'P2',
    assigneeId: 'qa-other',
    status: 'running',
    startedAt: '2026-06-20T03:00:00.000Z',
    createdBy: 'qa-other',
    createdAt: '2026-06-20T01:00:00.000Z',
    updatedAt: '2026-06-24T02:00:00.000Z',
    ...patch,
  };
}

function bug(patch: Partial<Bug> = {}): Bug {
  return {
    id: 'bug-1',
    bugNo: 'BUG-001',
    versionId: 'ver-1',
    testCaseId: 'tc-1',
    title: 'Warning count mismatch',
    description: 'The count is wrong.',
    severity: 'major',
    priority: 'P1',
    reportedBy: 'qa-other',
    assigneeId: 'dev-other',
    status: 'open',
    createdAt: '2026-06-20T01:00:00.000Z',
    updatedAt: '2026-06-24T02:00:00.000Z',
    ...patch,
  };
}

test('buildVersionDailyEvidence groups version activity and detects no activity/no update', () => {
  const workItems = buildXiaobaoWorkItems({
    plans: [plan()],
    devTasks: [devTask()],
    testCases: [testCase()],
    bugs: [bug()],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map([['req-1', 'ver-1']]),
  });
  const activities: WorkActivity[] = [
    {
      id: 'act-delivery',
      actorId: 'dev-other',
      date: '2026-06-29',
      occurredAt: '2026-06-29T02:00:00.000Z',
      sourceType: 'dev_task',
      sourceId: 'dev-1',
      action: 'dev_task_submitted',
      category: 'delivery',
      title: 'Build warning panel',
      summary: 'Submitted development task',
    },
    {
      id: 'act-risk',
      actorId: 'qa-other',
      date: '2026-06-29',
      occurredAt: '2026-06-29T03:00:00.000Z',
      sourceType: 'bug',
      sourceId: 'bug-1',
      action: 'bug_blocked',
      category: 'risk',
      title: 'Warning count mismatch',
      summary: 'Blocked by missing data',
    },
  ];
  const worklogs: TaskWorklog[] = [
    {
      id: 'wl-note',
      taskId: 'tc-1',
      userId: 'qa-other',
      date: '2026-06-29',
      hours: 1,
      workContent: 'Continued regression testing.',
      createdAt: '2026-06-29T04:00:00.000Z',
    },
  ];

  const evidence = buildVersionDailyEvidence({
    versionId: 'ver-1',
    workItems,
    activities,
    worklogs,
    now: new Date('2026-06-29T08:00:00.000Z'),
  });

  assert.deepEqual(evidence.todayDeliveries.map((item) => item.id), ['act-delivery']);
  assert.deepEqual(evidence.todayRisks.map((item) => item.id), ['act-risk']);
  assert.deepEqual(evidence.progressNotes.map((item) => item.id), ['wl-note']);
  assert.equal(evidence.recentActivityCount, 3);
  assert.equal(evidence.lastActivityAt, '2026-06-29T04:00:00.000Z');
  assert.ok(evidence.silentRisks?.some((risk) => risk.key === 'no_update' && risk.itemId === 'plan-1'));
  assert.ok(evidence.silentRisks?.some((risk) => risk.key === 'no_activity' && risk.itemId === 'plan-1'));
});

test('buildVersionDailyEvidence uses plan record work start time for daily hours', () => {
  const workItems = buildXiaobaoWorkItems({
    plans: [
      plan({
        id: 'plan-cross-day',
        title: 'Product plan',
        actualStartAt: '2026-06-30T01:00:00.000Z',
        createdAt: '2026-06-30T01:00:00.000Z',
      }),
    ],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map(),
  });
  const activities: WorkActivity[] = [
    {
      id: 'act-plan-record',
      actorId: 'pm-1',
      date: '2026-07-01',
      occurredAt: '2026-07-01T04:00:00.000Z',
      sourceType: 'version_plan',
      sourceId: 'plan-cross-day',
      action: 'version_plan_requirement_progress',
      category: 'progress',
      title: 'Product plan',
      summary: 'Updated product plan requirement progress',
      metadata: {
        requirementId: 'req-1',
        workStartedAt: '2026-07-01T02:00:00.000Z',
      },
    },
  ];

  const evidence = buildVersionDailyEvidence({
    versionId: 'ver-1',
    workItems,
    activities,
    worklogs: [],
    now: new Date('2026-07-01T08:00:00.000Z'),
  });

  assert.equal(evidence.todayActualHours, 2);
});

test('buildVersionDailyEvidence uses previous progress next start time for dev task daily hours', () => {
  const workItems = buildXiaobaoWorkItems({
    devTasks: [
      devTask({
        id: 'dev-cross-day-progress',
        title: 'Cross-day development',
        actualStartAt: '2026-07-01T01:30:00.000Z',
        updatedAt: '2026-07-02T10:00:00.000Z',
      }),
    ],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map([['req-1', 'ver-1']]),
  });
  const activities: WorkActivity[] = [
    {
      id: 'act-dev-progress-day-1',
      actorId: 'dev-1',
      date: '2026-07-01',
      occurredAt: '2026-07-01T10:00:00.000Z',
      sourceType: 'dev_task',
      sourceId: 'dev-cross-day-progress',
      action: 'progress_note_added',
      category: 'note',
      title: 'Cross-day development',
      summary: 'Updated today progress',
      metadata: {
        note: 'Finished the first part',
        nextStartAt: '2026-07-02T01:30:00.000Z',
      },
    },
    {
      id: 'act-dev-progress-day-2',
      actorId: 'dev-1',
      date: '2026-07-02',
      occurredAt: '2026-07-02T10:00:00.000Z',
      sourceType: 'dev_task',
      sourceId: 'dev-cross-day-progress',
      action: 'progress_note_added',
      category: 'note',
      title: 'Cross-day development',
      summary: 'Updated today progress',
      metadata: {
        note: 'Finished the second part',
        nextStartAt: '2026-07-03T01:30:00.000Z',
      },
    },
  ];

  const evidence = buildVersionDailyEvidence({
    versionId: 'ver-1',
    workItems,
    activities,
    worklogs: [],
    now: new Date('2026-07-02T10:00:00.000Z'),
  });

  assert.equal(evidence.todayActualHours, 7.5);
});

test('buildVersionDailyEvidence does not emit Infinity-day silent risk details', () => {
  const workItems = buildXiaobaoWorkItems({
    plans: [
      plan({
        id: 'plan-no-evidence',
        title: 'Plan without evidence',
        createdAt: '2026-06-20T01:00:00.000Z',
        actualStartAt: '2026-06-20T01:00:00.000Z',
      }),
    ],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map(),
  });

  const evidence = buildVersionDailyEvidence({
    versionId: 'ver-1',
    workItems,
    activities: [],
    worklogs: [],
    now: new Date('2026-06-29T08:00:00.000Z'),
  });

  assert.ok((evidence.silentRisks ?? []).length > 0);
  assert.equal((evidence.silentRisks ?? []).some((risk) => risk.detail.includes('Infinity')), false);
});

test('buildVersionDailyEvidence mirrors daily report timestamp fallback evidence', () => {
  const workItems = buildXiaobaoWorkItems({
    plans: [
      plan({
        id: 'plan-created',
        title: '新建产品方案',
        status: 'pending',
        createdAt: '2026-06-29T01:00:00.000Z',
        actualStartAt: undefined,
      }),
    ],
    devTasks: [
      devTask({
        id: 'dev-started',
        title: '开始开发风险列表',
        status: 'in_progress',
        actualStartAt: '2026-06-29T02:00:00.000Z',
        createdAt: '2026-06-28T01:00:00.000Z',
        updatedAt: '2026-06-29T02:00:00.000Z',
      }),
      devTask({
        id: 'dev-submitted',
        title: '提交风险列表',
        status: 'submitted',
        actualStartAt: '2026-06-28T02:00:00.000Z',
        actualEndAt: '2026-06-29T03:00:00.000Z',
        createdAt: '2026-06-28T01:00:00.000Z',
        updatedAt: '2026-06-29T03:00:00.000Z',
      }),
    ],
    testCases: [
      testCase({
        id: 'tc-failed',
        title: '验证风险列表失败态',
        status: 'failed',
        startedAt: '2026-06-29T03:30:00.000Z',
        completedAt: '2026-06-29T04:00:00.000Z',
        createdAt: '2026-06-28T01:00:00.000Z',
        updatedAt: '2026-06-29T04:00:00.000Z',
      }),
    ],
    bugs: [
      bug({
        id: 'bug-fixed',
        title: '风险列表数量错误',
        status: 'fixed',
        createdAt: '2026-06-28T01:00:00.000Z',
        resolvedAt: '2026-06-29T05:00:00.000Z',
        updatedAt: '2026-06-29T05:00:00.000Z',
      }),
    ],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map([['req-1', 'ver-1']]),
  });

  const evidence = buildVersionDailyEvidence({
    versionId: 'ver-1',
    workItems,
    activities: [],
    worklogs: [],
    now: new Date('2026-06-29T08:00:00.000Z'),
  });

  assert.deepEqual(evidence.todayCreations.map((item) => item.summary), ['新建计划：新建产品方案']);
  assert.ok(evidence.todayProgress.some((item) => item.summary === '开始开发：开始开发风险列表'));
  assert.ok(evidence.todayDeliveries.some((item) => item.summary === '已提测开发任务：提交风险列表'));
  assert.ok(evidence.todayDeliveries.some((item) => item.summary === '已修复 Bug：风险列表数量错误'));
  assert.ok(evidence.todayProgress.some((item) => item.summary === '开始测试：验证风险列表失败态'));
  assert.ok(evidence.todayRisks.some((item) => item.summary === '测试不通过：验证风险列表失败态'));
  assert.equal(evidence.totalActivityCount, 6);
  assert.equal(evidence.lastActivityAt, '2026-06-29T05:00:00.000Z');
  assert.ok(evidence.todayActualHours > 0);
});

test('buildXiaobaoWorkItems keeps all version work without current-user filtering', () => {
  const items = buildXiaobaoWorkItems({
    plans: [plan({ owner: 'pm-other' })],
    devTasks: [devTask({ assigneeId: 'dev-other' })],
    testCases: [testCase({ assigneeId: 'qa-other' })],
    bugs: [bug({ assigneeId: 'dev-other' })],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map([['req-1', 'ver-1']]),
  });

  assert.deepEqual(items.map((item) => item.id), ['plan-1', 'dev-1', 'tc-1', 'bug-1']);
  assert.deepEqual(items.map((item) => item.versionId), ['ver-1', 'ver-1', 'ver-1', 'ver-1']);
});

test('buildXiaobaoWorkItems uses direct version id for no-requirement dev tasks', () => {
  const items = buildXiaobaoWorkItems({
    devTasks: [
      devTask({
        id: 'dev-no-req',
        versionId: 'ver-1',
        requirementId: '',
        requirementName: '预入职人员支持',
      }),
    ],
    versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
    requirementVersionMap: new Map(),
  });

  assert.equal(items[0].versionId, 'ver-1');
  assert.equal(items[0].versionName, 'V1.0');
});
