import { mapAppDataToV22Rows } from './app-data-v22.mapper';

const now = '2026-01-04T10:00:00.000Z';

function buildAppData(): Record<string, any> {
  return {
    'products-overview': [
      {
        id: 'product-1',
        name: 'FTB',
        description: 'Product suite',
        createdAt: '2026-01-01T00:00:00.000Z',
        updatedAt: '2026-01-02T00:00:00.000Z',
        projects: [
          {
            id: 'project-1',
            name: 'CRM',
            description: 'Customer project',
            createdAt: '2026-01-01T01:00:00.000Z',
          },
        ],
        versions: [
          {
            id: 'version-1',
            name: 'CRM V1.0',
            description: 'First release',
            status: 'in_progress',
            releaseDate: '2026-02-01',
            expectedReleaseDate: '2026-02-03',
            createdAt: '2026-01-01T02:00:00.000Z',
            updatedAt: '2026-01-02T02:00:00.000Z',
          },
        ],
      },
    ],
    requirements: {
      requirements: [
        {
          id: 'req-1',
          code: 'REQ-001',
          title: 'Customer import',
          description: 'Import customers in bulk',
          productId: 'product-1',
          projectId: 'project-1',
          versionId: 'version-1',
          sourceType: 'customer',
          sourceTarget: 'ACME',
          platforms: ['Web', 'App'],
          typeId: 'type-feature',
          status: 'adopted',
          priority: 'P1',
          creator: 'member-pm',
          createdAt: '2026-01-02T08:00:00.000Z',
          updatedAt: '2026-01-02T09:00:00.000Z',
        },
      ],
    },
    members: {
      members: [
        {
          id: 'member-pm',
          name: 'Product manager',
          username: 'pm',
          email: '',
          createdAt: '2026-01-01T00:00:00.000Z',
        },
        {
          id: 'member-dev',
          name: 'Developer',
          username: 'dev',
          email: 'dev@example.com',
          createdAt: '2026-01-01T00:00:00.000Z',
        },
        {
          id: 'member-test',
          name: 'Tester',
          username: 'test',
          email: '',
          createdAt: '2026-01-01T00:00:00.000Z',
        },
      ],
    },
    'task-categories': [
      {
        id: 'cat-fe',
        code: 'frontend_development',
        name: 'Frontend development',
        group: 'development',
        isSystem: true,
      },
      {
        id: 'cat-test',
        code: 'test_functional',
        name: 'Functional test',
        group: 'testing',
        isSystem: true,
      },
    ],
    'version-plans': [
      {
        id: 'plan-1',
        versionId: 'version-1',
        type: 'product',
        title: 'Product plan',
        owner: 'member-pm',
        startTime: '2026-01-02T09:00:00.000Z',
        endTime: '2026-01-02T18:00:00.000Z',
        status: 'completed',
        requirementCoverage: [
          {
            requirementId: 'req-1',
            status: 'completed',
            updatedAt: now,
            updatedBy: 'member-pm',
          },
        ],
        logs: [
          {
            id: 'plan-log-1',
            type: 'requirement_progress',
            createdAt: now,
            actor: 'member-pm',
            title: 'Requirement completed',
          },
        ],
        resultUrl: 'https://example.com/prototype',
        createdAt: '2026-01-02T08:30:00.000Z',
        completedAt: '2026-01-02T17:00:00.000Z',
        addedBy: 'member-pm',
      },
    ],
    'dev-tasks': [
      {
        id: 'dev-1',
        taskNo: 'DEV-001',
        requirementId: 'req-1',
        title: 'Build import UI',
        description: 'Upload and preview CSV',
        categoryId: 'cat-fe',
        assigneeId: 'member-dev',
        priority: 'P0',
        expectedStartAt: '2026-01-03T09:00:00.000Z',
        expectedEndAt: '2026-01-03T18:00:00.000Z',
        actualStartAt: '2026-01-03T10:00:00.000Z',
        actualEndAt: '2026-01-03T17:30:00.000Z',
        estimateHours: 6,
        aiEstimateHours: 7,
        status: 'submitted',
        isBlocked: false,
        references: [{ type: 'requirement', id: 'req-1', label: 'REQ-001' }],
        aiDraft: false,
        createdBy: 'member-pm',
        createdAt: '2026-01-03T08:30:00.000Z',
        updatedAt: '2026-01-03T17:30:00.000Z',
      },
    ],
    'test-cases': [
      {
        id: 'tc-1',
        caseNo: 'TC-001',
        versionId: 'version-1',
        requirementId: 'req-1',
        title: 'Import success path',
        description: 'Upload a valid CSV',
        categoryId: 'cat-test',
        priority: 'P2',
        assigneeId: 'member-test',
        status: 'failed',
        roundNo: 1,
        plannedTestAt: '2026-01-04T09:00:00.000Z',
        plannedEndAt: '2026-01-04T12:00:00.000Z',
        startedAt: '2026-01-04T09:30:00.000Z',
        completedAt: '2026-01-04T10:30:00.000Z',
        estimateHours: 2,
        aiEstimateHours: 2.5,
        references: [{ type: 'requirement', id: 'req-1', label: 'REQ-001' }],
        createdBy: 'member-test',
        createdAt: '2026-01-04T08:00:00.000Z',
        updatedAt: '2026-01-04T10:30:00.000Z',
      },
    ],
    bugs: [
      {
        id: 'bug-1',
        bugNo: 'BUG-001',
        versionId: 'version-1',
        testCaseId: 'tc-1',
        requirementId: 'req-1',
        title: 'Preview count is wrong',
        description: 'Total rows shows 0',
        severity: 'major',
        priority: 'P1',
        reportedBy: 'member-test',
        assigneeId: 'member-dev',
        status: 'fixing',
        plannedFixAt: '2026-01-04T18:00:00.000Z',
        createdAt: '2026-01-04T10:40:00.000Z',
        updatedAt: '2026-01-04T11:00:00.000Z',
      },
    ],
    'work-activities': [
      {
        id: 'activity-1',
        actorId: 'member-dev',
        date: '2026-01-03',
        occurredAt: '2026-01-03T10:00:00.000Z',
        sourceType: 'dev_task',
        sourceId: 'dev-1',
        action: 'dev_task_started',
        category: 'progress',
        title: 'Started import UI',
        summary: 'Started development',
        metadata: { toStatus: 'in_progress' },
      },
    ],
    'task-worklogs': [
      {
        id: 'worklog-1',
        taskId: 'dev-1',
        userId: 'member-dev',
        date: '2026-01-03',
        hours: 2.5,
        workContent: 'Built CSV preview',
        createdAt: '2026-01-03T19:00:00.000Z',
      },
    ],
    overtime: {
      records: [
        {
          id: 'overtime-1',
          projectId: 'project-1',
          versionId: 'version-1',
          person: 'member-dev',
          startTime: '2026-01-03T18:00:00.000Z',
          endTime: '2026-01-03T20:00:00.000Z',
          duration: 2,
          reasonId: 'reason-3',
          remark: 'Release sprint',
          createdAt: '2026-01-03T20:10:00.000Z',
        },
      ],
    },
    'xiaobao-risk-snapshots': [
      {
        versionId: 'version-1',
        date: '2026-01-04',
        riskScore: 72,
        riskLevel: 'at_risk',
        forecastReleaseDate: '2026-02-05',
        openBugCount: 3,
        criticalBugCount: 1,
        failedTestCount: 2,
        blockedCount: 1,
        silentRiskCount: 0,
        confidence: 80,
        createdAt: '2026-01-04T12:00:00.000Z',
      },
    ],
    'xiaobao-risk-insights': [
      {
        versionId: 'version-1',
        riskSignature: 'risk-signature-1',
        insight: { summary: 'Risk is rising', why: ['Bug count rose'] },
        generatedAt: '2026-01-04T12:05:00.000Z',
        providerInfo: { providerId: 'anthropic', model: 'claude-test' },
      },
    ],
  };
}

describe('mapAppDataToV22Rows', () => {
  it('maps AppData entities into partition-key-ready relational rows', () => {
    const result = mapAppDataToV22Rows(buildAppData());

    expect(result.products).toEqual([
      expect.objectContaining({ id: 'product-1', name: 'FTB' }),
    ]);
    expect(result.projects).toEqual([
      expect.objectContaining({ id: 'project-1', productId: 'product-1', name: 'CRM' }),
    ]);
    expect(result.versions).toEqual([
      expect.objectContaining({
        id: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        releaseDate: '2026-02-01',
      }),
    ]);
    expect(result.users).toEqual([
      expect.objectContaining({ id: 'member-pm', email: 'pm@local.ftb', name: 'Product manager' }),
      expect.objectContaining({ id: 'member-dev', email: 'dev@example.com', name: 'Developer' }),
      expect.objectContaining({ id: 'member-test', email: 'test@local.ftb', name: 'Tester' }),
    ]);

    expect(result.requirements).toEqual([
      expect.objectContaining({
        id: 'req-1',
        productId: 'product-1',
        projectId: 'project-1',
        versionId: 'version-1',
        code: 'REQ-001',
        priority: 1,
        platform: 'Web,App',
        creatorId: 'member-pm',
      }),
    ]);
    expect(result.devTasks).toEqual([
      expect.objectContaining({
        id: 'dev-1',
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        requirementId: 'req-1',
        requirementProductId: 'product-1',
        code: 'DEV-001',
        priority: 0,
        startDate: '2026-01-03T10:00:00.000Z',
        completedAt: '2026-01-03T17:30:00.000Z',
      }),
    ]);
    expect(result.testCases).toEqual([
      expect.objectContaining({
        id: 'tc-1',
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        requirementProductId: 'product-1',
        code: 'TC-001',
        priority: 2,
      }),
    ]);
    expect(result.bugs).toEqual([
      expect.objectContaining({
        id: 'bug-1',
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        testCaseId: 'tc-1',
        testCaseVersionId: 'version-1',
        code: 'BUG-001',
        priority: 1,
      }),
    ]);
    expect(result.skipped).toEqual([]);
  });

  it('maps append-only activity, worklog, overtime, and Xiaobao rows with createdAt partition keys', () => {
    const result = mapAppDataToV22Rows(buildAppData());

    expect(result.workActivities).toEqual([
      expect.objectContaining({
        id: 'activity-1',
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        sourceType: 'dev_task',
        sourceId: 'dev-1',
        sourceVersionId: 'version-1',
        occurredAt: '2026-01-03T10:00:00.000Z',
        createdAt: '2026-01-03T10:00:00.000Z',
      }),
    ]);
    expect(result.taskWorklogs).toEqual([
      expect.objectContaining({
        id: 'worklog-1',
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        sourceType: 'dev_task',
        sourceId: 'dev-1',
        sourceVersionId: 'version-1',
        workDate: '2026-01-03',
        createdAt: '2026-01-03T19:00:00.000Z',
      }),
    ]);
    expect(result.overtimeRecords).toEqual([
      expect.objectContaining({
        id: 'overtime-1',
        productId: 'product-1',
        projectId: 'project-1',
        versionId: 'version-1',
        userId: 'member-dev',
        reason: 'reason-3',
        hours: 2,
        createdAt: '2026-01-03T20:10:00.000Z',
      }),
    ]);
    expect(result.xiaobaoRiskSnapshots).toEqual([
      expect.objectContaining({
        versionId: 'version-1',
        snapshotDate: '2026-01-04',
        riskLevel: 'at_risk',
        riskScore: 72,
        riskSignature: 'version-1|2026-01-04|72|at_risk|2026-02-05|3|1|2|1|0|80',
        createdAt: '2026-01-04T12:00:00.000Z',
      }),
    ]);
    expect(result.xiaobaoRiskInsights).toEqual([
      expect.objectContaining({
        versionId: 'version-1',
        riskSignature: 'risk-signature-1',
        status: 'generated',
        createdAt: '2026-01-04T12:05:00.000Z',
      }),
    ]);
    expect(result.xiaobaoRiskSummaries).toEqual([
      expect.objectContaining({
        versionId: 'version-1',
        riskLevel: 'at_risk',
        riskScore: 72,
        confidence: 80,
        riskSignature: 'version-1|2026-01-04|72|at_risk|2026-02-05|3|1|2|1|0|80',
      }),
    ]);
  });

  it('skips rows that cannot resolve the partition key instead of inventing unsafe ownership', () => {
    const appData = buildAppData();
    appData['dev-tasks'].push({
      id: 'dev-orphan',
      taskNo: 'DEV-999',
      requirementId: 'missing-req',
      title: 'Cannot resolve version',
      categoryId: 'cat-fe',
      assigneeId: 'member-dev',
      priority: 'P2',
      expectedStartAt: '',
      expectedEndAt: '',
      status: 'todo',
      isBlocked: false,
      createdBy: 'member-pm',
      createdAt: now,
      updatedAt: now,
    });

    const result = mapAppDataToV22Rows(appData);

    expect(result.devTasks.map((task: { id: string }) => task.id)).toEqual(['dev-1']);
    expect(result.skipped).toContainEqual({
      key: 'dev-tasks',
      id: 'dev-orphan',
      reason: 'missing version partition context',
    });
  });
});
