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

import * as versionPlan from './version-plan';
import type { VersionPlan } from './version-plan';

function plan(patch: Partial<VersionPlan>): VersionPlan {
  return {
    id: 'plan-1',
    versionId: 'version-1',
    type: 'product',
    title: '产品方案',
    owner: 'PM',
    startTime: '2026-06-25T09:00',
    endTime: '2026-06-25T18:00',
    status: 'pending',
    createdAt: '2026-06-25',
    addedBy: 'PM',
    ...patch,
  };
}

test('sortPlansNewestFirst places newly created plans before older plans', () => {
  const sortPlansNewestFirst = (versionPlan as any).sortPlansNewestFirst as undefined | ((plans: VersionPlan[]) => VersionPlan[]);
  assert.equal(typeof sortPlansNewestFirst, 'function');

  const plans = [
    plan({ id: 'plan-100', createdAt: '2026-06-26' }),
    plan({ id: 'manual-old', createdAt: '2026-06-25' }),
    plan({ id: 'plan-300', createdAt: '2026-06-26' }),
  ];

  const sorted = (sortPlansNewestFirst as (items: VersionPlan[]) => VersionPlan[])(plans);

  assert.deepEqual(sorted.map((item) => item.id), ['plan-300', 'plan-100', 'manual-old']);
  assert.deepEqual(plans.map((item) => item.id), ['plan-100', 'manual-old', 'plan-300']);
});

test('collects logs across plans with plan context and newest first', () => {
  const getPlanLogsForPlans = (versionPlan as any).getPlanLogsForPlans as undefined | ((plans: VersionPlan[]) => Array<{
    id: string;
    planId: string;
    planTitle: string;
    createdAt: string;
  }>);
  assert.equal(typeof getPlanLogsForPlans, 'function');

  const logs = getPlanLogsForPlans!([
    plan({
      id: 'plan-a',
      title: '产品方案第一天',
      logs: [
        {
          id: 'log-old',
          type: 'system',
          title: '开始计划',
          actor: 'PM',
          createdAt: '2026-06-29T09:00:00.000Z',
        },
      ],
    }),
    plan({
      id: 'plan-b',
      title: '产品方案第二天',
      logs: [
        {
          id: 'log-new',
          type: 'requirement_progress',
          title: '更新需求进度',
          actor: 'PM',
          createdAt: '2026-06-29T15:00:00.000Z',
        },
      ],
    }),
  ]);

  assert.deepEqual(logs.map((log) => ({
    id: log.id,
    planId: log.planId,
    planTitle: log.planTitle,
  })), [
    { id: 'log-new', planId: 'plan-b', planTitle: '产品方案第二天' },
    { id: 'log-old', planId: 'plan-a', planTitle: '产品方案第一天' },
  ]);
});

test('derives requirement coverage from new records and legacy completed ids', () => {
  const getRequirementCoverageStatus = (versionPlan as any).getRequirementCoverageStatus as undefined | ((item: VersionPlan, requirementId: string) => string);
  const getRequirementCoverageSummary = (versionPlan as any).getRequirementCoverageSummary as undefined | ((item: VersionPlan) => {
    total: number;
    completed: number;
    partial: number;
    notStarted: number;
    percent: number;
  });
  assert.equal(typeof getRequirementCoverageStatus, 'function');
  assert.equal(typeof getRequirementCoverageSummary, 'function');

  const item = plan({
    linkedRequirementIds: ['r1', 'r2', 'r3', 'r4'],
    completedRequirementIds: ['r2'],
    requirementCoverage: [
      {
        requirementId: 'r1',
        status: 'partial',
        completedContent: '完成主流程原型',
        remainingContent: '补充异常状态',
        updatedAt: '2026-06-29T09:00:00.000Z',
        updatedBy: 'PM',
      },
      {
        requirementId: 'r3',
        status: 'completed',
        completedContent: '已覆盖列表和详情',
        updatedAt: '2026-06-29T10:00:00.000Z',
        updatedBy: 'PM',
      },
    ],
  } as Partial<VersionPlan>);

  assert.equal(getRequirementCoverageStatus!(item, 'r1'), 'partial');
  assert.equal(getRequirementCoverageStatus!(item, 'r2'), 'completed');
  assert.equal(getRequirementCoverageStatus!(item, 'r4'), 'not_started');
  assert.deepEqual(getRequirementCoverageSummary!(item), {
    total: 4,
    completed: 2,
    partial: 1,
    notStarted: 1,
    percent: 50,
  });
});

test('updates requirement coverage, syncs legacy completed ids, and creates a plan log', () => {
  const updateRequirementCoverage = (versionPlan as any).updateRequirementCoverage as undefined | ((item: VersionPlan, input: {
    requirementId: string;
    status: string;
    completedContent?: string;
    remainingContent?: string;
    updatedBy: string;
    updatedAt: string;
    requirementCode?: string;
    requirementTitle?: string;
  }) => any);
  assert.equal(typeof updateRequirementCoverage, 'function');

  const next = updateRequirementCoverage!(plan({
    linkedRequirementIds: ['r1'],
    completedRequirementIds: ['r1'],
    requirementCoverage: [
      {
        requirementId: 'r1',
        status: 'completed',
        currentWorkStartedAt: '2026-06-29T09:30:00.000Z',
        updatedAt: '2026-06-28T12:00:00.000Z',
        updatedBy: 'PM',
      },
    ],
  }), {
    requirementId: 'r1',
    status: 'partial',
    completedContent: '完成移动端主流程',
    remainingContent: 'PC 端筛选规则未完成',
    updatedBy: 'PM',
    updatedAt: '2026-06-29T12:00:00.000Z',
    requirementCode: 'QY0001',
    requirementTitle: '需求池筛选',
  });

  assert.deepEqual(next.completedRequirementIds, []);
  assert.equal(next.requirementCoverage?.[0]?.status, 'partial');
  assert.equal(next.requirementCoverage?.[0]?.currentWorkStartedAt, undefined);
  assert.equal(next.logs?.length, 1);
  assert.equal(next.logs?.[0]?.type, 'requirement_progress');
  assert.equal(next.logs?.[0]?.actor, 'PM');
  assert.equal(next.logs?.[0]?.requirementCode, 'QY0001');
  assert.equal(next.logs?.[0]?.completedContent, '完成移动端主流程');
  assert.equal(next.logs?.[0]?.remainingContent, 'PC 端筛选规则未完成');
  assert.equal(next.logs?.[0]?.workStartedAt, '2026-06-29T09:30:00.000Z');
});

test('starts requirement coverage work while preserving existing progress', () => {
  const startRequirementCoverageWork = (versionPlan as any).startRequirementCoverageWork as undefined | ((item: VersionPlan, input: {
    requirementId: string;
    startedAt: string;
    updatedBy: string;
  }) => any);
  assert.equal(typeof startRequirementCoverageWork, 'function');

  const next = startRequirementCoverageWork!(plan({
    requirementCoverage: [
      {
        requirementId: 'r1',
        status: 'partial',
        completedContent: '完成主流程',
        remainingContent: '补充异常状态',
        updatedAt: '2026-06-28T12:00:00.000Z',
        updatedBy: 'PM',
      },
    ],
  }), {
    requirementId: 'r1',
    startedAt: '2026-06-29T09:30:00.000Z',
    updatedBy: 'PM',
  });

  assert.equal(next.requirementCoverage?.[0]?.status, 'partial');
  assert.equal(next.requirementCoverage?.[0]?.completedContent, '完成主流程');
  assert.equal(next.requirementCoverage?.[0]?.remainingContent, '补充异常状态');
  assert.equal(next.requirementCoverage?.[0]?.currentWorkStartedAt, '2026-06-29T09:30:00.000Z');
  assert.equal(next.requirementCoverage?.[0]?.updatedBy, 'PM');
});

test('validates requirement coverage record drafts by started work session', () => {
  const canSaveRequirementCoverageDraft = (versionPlan as any).canSaveRequirementCoverageDraft as undefined | ((
    status: string,
    completedContent?: string,
    remainingContent?: string,
    workStartedAt?: string,
  ) => boolean);
  assert.equal(typeof canSaveRequirementCoverageDraft, 'function');

  assert.equal(canSaveRequirementCoverageDraft!('completed'), false);
  assert.equal(canSaveRequirementCoverageDraft!('completed', undefined, undefined, '2026-06-29T09:30:00.000Z'), true);
  assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '', '2026-06-29T09:30:00.000Z'), false);
  assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '补充异常状态'), false);
  assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '补充异常状态', '2026-06-29T09:30:00.000Z'), true);
  assert.equal(canSaveRequirementCoverageDraft!('not_started', undefined, undefined, '2026-06-29T09:30:00.000Z'), false);
});

test('hides coverage record action after a requirement is completed', () => {
  const canOpenRequirementCoverageRecord = (versionPlan as any).canOpenRequirementCoverageRecord as undefined | ((
    status: string,
    canEdit: boolean,
  ) => boolean);
  assert.equal(typeof canOpenRequirementCoverageRecord, 'function');

  assert.equal(canOpenRequirementCoverageRecord!('not_started', true), true);
  assert.equal(canOpenRequirementCoverageRecord!('partial', true), true);
  assert.equal(canOpenRequirementCoverageRecord!('completed', true), false);
  assert.equal(canOpenRequirementCoverageRecord!('partial', false), false);
});

test('keeps research direction presets visible while disabling selected presets', () => {
  const getResearchDirectionPresetOptions = (versionPlan as any).getResearchDirectionPresetOptions as undefined | ((
    tasks: Array<{ title: string }>,
  ) => Array<{ title: string; disabled: boolean }>);
  assert.equal(typeof getResearchDirectionPresetOptions, 'function');

  const options = getResearchDirectionPresetOptions!([{ title: '竞品分析' }]);

  assert.ok(options.length >= 6);
  assert.equal(options.find((option) => option.title === '竞品分析')?.disabled, true);
  assert.equal(options.find((option) => option.title === '用户访谈')?.disabled, false);
});
