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

import { getPlanCompletionState, hasPlanResult } from './version-plan-workflow';
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: 'in_progress',
    linkedRequirementIds: ['r1'],
    completedRequirementIds: [],
    createdAt: '2026-06-25',
    addedBy: 'PM',
    ...patch,
  };
}

test('research requires direction completion instead of linked requirement coverage', () => {
  const state = getPlanCompletionState(plan({
    type: 'research',
    tasks: [{ id: 'task-1', title: '调研方向', status: 'pending' }],
    linkedRequirementIds: ['r1'],
  }));
  assert.equal(state.canSubmitResult, false);
  assert.ok(state.missingReasons.includes('调研方向未全部完成'));
  assert.equal(state.missingReasons.includes('关联需求未全部覆盖'), false);
});

test('requires product requirement coverage when linked requirements exist', () => {
  const state = getPlanCompletionState(plan({}));
  assert.equal(state.canSubmitResult, false);
  assert.ok(state.missingReasons.includes('关联需求未全部覆盖'));
});

test('does not treat partial requirement coverage as complete', () => {
  const state = getPlanCompletionState(plan({
    requirementCoverage: [{
      requirementId: 'r1',
      status: 'partial',
      completedContent: '完成列表主路径',
      remainingContent: '剩余筛选联动和空状态',
      updatedAt: '2026-06-29T09:00:00.000Z',
      updatedBy: 'PM',
    }],
  } as Partial<VersionPlan>));

  assert.equal(state.requirementCompleted, 0);
  assert.equal(state.canSubmitResult, false);
  assert.ok(state.missingReasons.includes('关联需求未全部覆盖'));
});

test('uses requirement coverage before legacy completed ids when both exist', () => {
  const state = getPlanCompletionState(plan({
    completedRequirementIds: ['r1'],
    requirementCoverage: [{
      requirementId: 'r1',
      status: 'partial',
      completedContent: '完成移动端',
      remainingContent: 'PC 端未完成',
      updatedAt: '2026-06-29T09:00:00.000Z',
      updatedBy: 'PM',
    }],
  } as Partial<VersionPlan>));

  assert.equal(state.requirementCompleted, 0);
  assert.equal(state.canSubmitResult, false);
});

test('allows product result submission after coverage is complete without task checklist', () => {
  const state = getPlanCompletionState(plan({
    completedRequirementIds: ['r1'],
  }));
  assert.equal(state.canSubmitResult, true);
  assert.equal(state.canComplete, false);
});

test('allows completion only after result exists', () => {
  const state = getPlanCompletionState(plan({
    completedRequirementIds: ['r1'],
    resultType: 'link',
    resultTitle: '原型',
    resultUrl: 'https://example.com/prototype',
    prototypeReviewConfirmed: true,
  }));
  assert.equal(state.canComplete, true);
});

test('ui plan does not require task checklist', () => {
  const state = getPlanCompletionState(plan({
    type: 'ui',
    completedRequirementIds: ['r1'],
  }));
  assert.equal(state.canSubmitResult, true);
});

test('research requires completed directions and result but not linked requirement coverage', () => {
  const state = getPlanCompletionState(plan({
    type: 'research',
    tasks: [{ id: 'task-1', title: '调研', status: 'completed' }],
    linkedRequirementIds: ['r1'],
    completedRequirementIds: [],
    resultType: 'file',
    resultTitle: '调研报告',
    resultFileName: 'report.pdf',
    resultFileData: 'data:application/pdf;base64,abc',
  }));
  assert.equal(state.canComplete, true);
});

test('detects link and file result payloads', () => {
  assert.equal(hasPlanResult({ resultType: 'link', resultTitle: '原型', resultUrl: 'https://example.com' }), true);
  assert.equal(hasPlanResult({ resultType: 'file', resultTitle: '文件', resultFileName: 'a.pdf', resultFileData: 'data:pdf' }), true);
  assert.equal(hasPlanResult({ resultType: 'link', resultTitle: '原型' }), false);
});

test('product design plans require a prototype link and review confirmation', () => {
  const withoutReviewConfirmation = getPlanCompletionState(plan({
    productPlanKind: 'design',
    completedRequirementIds: ['r1'],
    resultType: 'link',
    resultTitle: 'Prototype',
    resultUrl: 'https://example.com/prototype',
  } as Partial<VersionPlan>));
  assert.equal(withoutReviewConfirmation.canComplete, false);

  const withReviewConfirmation = getPlanCompletionState(plan({
    productPlanKind: 'design',
    completedRequirementIds: ['r1'],
    resultType: 'link',
    resultTitle: 'Prototype',
    resultUrl: 'https://example.com/prototype',
    prototypeReviewConfirmed: true,
  } as Partial<VersionPlan>));
  assert.equal(withReviewConfirmation.canComplete, true);
});

test('product design plans do not accept file results', () => {
  assert.equal(hasPlanResult({
    productPlanKind: 'design',
    resultType: 'file',
    resultTitle: 'Axure file',
    resultFileName: 'prototype.rp',
    resultFileData: 'data:application/octet-stream;base64,abc',
  } as any), false);
});

test('product review plans can complete with a pass result without prototype link', () => {
  const state = getPlanCompletionState(plan({
    productPlanKind: 'review',
    completedRequirementIds: ['r1'],
    reviewResult: 'passed',
  } as Partial<VersionPlan>));
  assert.equal(state.canComplete, true);
});

test('product review plans require failure type and detail when review fails', () => {
  const missingFailureDetail = getPlanCompletionState(plan({
    productPlanKind: 'review',
    completedRequirementIds: ['r1'],
    reviewResult: 'failed',
  } as Partial<VersionPlan>));
  assert.equal(missingFailureDetail.canComplete, false);

  const completeFailureDetail = getPlanCompletionState(plan({
    productPlanKind: 'review',
    completedRequirementIds: ['r1'],
    reviewResult: 'failed',
    reviewFailureTypes: ['interaction_flow'],
    reviewFailureReason: 'Critical path is missing empty and rollback states.',
  } as Partial<VersionPlan>));
  assert.equal(completeFailureDetail.canComplete, true);
});
