import { APP_DATA_KEYS } from '../data/data-keys';
import { AppDataV22MigrationService, normalizeDateTimeFields } from './app-data-v22.migration.service';

describe('AppDataV22MigrationService', () => {
  it('normalizes date-only fields used by relation-table writes', () => {
    expect(
      normalizeDateTimeFields({
        workDate: '2026-07-03',
        snapshotDate: '2026-07-03',
        createdAt: '2026-07-03',
      }),
    ).toEqual({
      workDate: '2026-07-03T00:00:00.000Z',
      snapshotDate: '2026-07-03T00:00:00.000Z',
      createdAt: '2026-07-03T00:00:00.000Z',
    });
  });

  it('loads allowed AppData keys and returns a migration preview without writing domain tables', async () => {
    const findMany = jest.fn().mockResolvedValue([
      {
        key: 'products-overview',
        value: [
          {
            id: 'product-1',
            name: 'FTB',
            projects: [{ id: 'project-1', name: 'CRM', description: '', createdAt: '2026-01-01T00:00:00.000Z' }],
            versions: [{ id: 'version-1', name: 'CRM V1.0', createdAt: '2026-01-01T00:00:00.000Z' }],
          },
        ],
      },
      {
        key: 'members',
        value: {
          members: [
            {
              id: 'member-pm',
              name: 'Product manager',
              username: 'pm',
              email: '',
              createdAt: '2026-01-01T00:00:00.000Z',
            },
          ],
        },
      },
      {
        key: 'requirements',
        value: {
          requirements: [
            {
              id: 'req-1',
              code: 'REQ-001',
              productId: 'product-1',
              projectId: 'project-1',
              versionId: 'version-1',
              title: 'Customer import',
              creator: 'member-pm',
              createdAt: '2026-01-01T00:00:00.000Z',
            },
          ],
        },
      },
      {
        key: 'dev-tasks',
        value: [
          {
            id: 'dev-1',
            taskNo: 'DEV-001',
            requirementId: 'req-1',
            title: 'Build import UI',
            status: 'todo',
            isBlocked: false,
            createdAt: '2026-01-01T00:00:00.000Z',
            updatedAt: '2026-01-01T00:00:00.000Z',
          },
        ],
      },
    ]);
    const createMany = jest.fn();
    const prisma = { appData: { findMany }, requirement: { createMany } };
    const service = new AppDataV22MigrationService(prisma as any);

    const preview = await service.preview();

    expect(findMany).toHaveBeenCalledWith({
      where: { key: { in: APP_DATA_KEYS } },
      select: { key: true, value: true },
    });
    expect(createMany).not.toHaveBeenCalled();
    expect(preview.readyToImport).toBe(true);
    expect(preview.counts).toEqual(
      expect.objectContaining({
        products: 1,
        projects: 1,
        versions: 1,
        users: 1,
        requirements: 1,
        devTasks: 1,
      }),
    );
    expect(preview.skipped).toEqual([]);
  });

  it('imports mapped rows in foreign-key-safe order with duplicate protection', async () => {
    const calls: string[] = [];
    const delegate = (name: string) => ({
      createMany: jest.fn().mockImplementation(async () => {
        calls.push(name);
        return { count: 1 };
      }),
    });
    const tx = {
      user: delegate('user'),
      product: delegate('product'),
      project: delegate('project'),
      version: delegate('version'),
      taskCategory: delegate('taskCategory'),
      requirement: delegate('requirement'),
      versionPlan: delegate('versionPlan'),
      devTask: delegate('devTask'),
      testCase: delegate('testCase'),
      bug: delegate('bug'),
      workActivity: delegate('workActivity'),
      taskWorklog: delegate('taskWorklog'),
      overtimeRecord: delegate('overtimeRecord'),
      xiaobaoRiskSnapshot: delegate('xiaobaoRiskSnapshot'),
      xiaobaoRiskInsight: delegate('xiaobaoRiskInsight'),
      xiaobaoRiskSummary: delegate('xiaobaoRiskSummary'),
    };
    const prisma = {
      $transaction: jest.fn().mockImplementation(async (callback: (client: typeof tx) => Promise<unknown>) => callback(tx)),
      appData: { findMany: jest.fn() },
    };
    const service = new AppDataV22MigrationService(prisma as any);
    const mapped = service.mapSnapshot({
      'products-overview': [
        {
          id: 'product-1',
          name: 'FTB',
          projects: [{ id: 'project-1', name: 'CRM', description: '', createdAt: '2026-01-01T00:00:00.000Z' }],
          versions: [{ id: 'version-1', name: 'CRM V1.0', createdAt: '2026-01-01T00:00:00.000Z' }],
        },
      ],
      members: {
        members: [{ id: 'member-pm', name: 'Product manager', username: 'pm', email: '', createdAt: '2026-01-01' }],
      },
      'task-categories': [
        {
          id: 'cat-fe',
          code: 'frontend_development',
          name: 'Frontend development',
          group: 'development',
          isSystem: true,
        },
      ],
      requirements: {
        requirements: [
          {
            id: 'req-1',
            code: 'REQ-001',
            productId: 'product-1',
            projectId: 'project-1',
            versionId: 'version-1',
            title: 'Customer import',
            creator: 'member-pm',
            createdAt: '2026-01-01T00:00:00.000Z',
          },
        ],
      },
    });

    const result = await service.importMappedRows(mapped);

    expect(result.readyToImport).toBe(true);
    expect(result.inserted).toEqual(expect.objectContaining({ users: 1, products: 1, requirements: 1 }));
    expect(calls.slice(0, 6)).toEqual(['user', 'product', 'project', 'version', 'taskCategory', 'requirement']);
    expect(tx.user.createMany).toHaveBeenCalledWith({
      data: [expect.objectContaining({
        id: 'member-pm',
        email: 'pm@local.ftb',
        createdAt: '2026-01-01T00:00:00.000Z',
      })],
      skipDuplicates: true,
    });
    expect(tx.requirement.createMany).toHaveBeenCalledWith({
      data: [expect.objectContaining({ creatorId: 'member-pm' })],
      skipDuplicates: true,
    });
  });
});
