import { describe, expect, it } from 'vitest';
import {
  migrationKey,
  findMissingReferenceMigrations,
  referenceMigrationNames,
} from '../squash-integrity.js';

describe('migrationKey — reduce a path to a comparable migration name', () => {
  it('strips directory and .cs', () => {
    expect(migrationKey('src/App/Migrations/core_v1_0_0_001_InitialCreate.cs')).toBe(
      'core_v1_0_0_001_InitialCreate',
    );
  });
  it('strips a .Designer.cs sidecar to the same key as its migration', () => {
    expect(migrationKey('src/App/Migrations/core_v1_0_0_001_InitialCreate.Designer.cs')).toBe(
      'core_v1_0_0_001_InitialCreate',
    );
  });
  it('normalizes Windows backslashes', () => {
    expect(migrationKey('src\\App\\Migrations\\ext_v2_0_0_003_AddOrders.cs')).toBe(
      'ext_v2_0_0_003_AddOrders',
    );
  });
  it('ignores the model snapshot', () => {
    expect(migrationKey('src/App/Migrations/CoreDbContextModelSnapshot.cs')).toBeNull();
  });
  it('ignores non-.cs files', () => {
    expect(migrationKey('src/App/Migrations/notes.txt')).toBeNull();
    expect(migrationKey('')).toBeNull();
  });
});

describe('findMissingReferenceMigrations — the prod-break signal', () => {
  const ref = [
    'src/App/Migrations/core_v3_54_0_001_InitialCreate.cs',
    'src/App/Migrations/core_v3_54_0_001_InitialCreate.Designer.cs',
    'src/App/Migrations/core_v3_54_0_002_AddInvoices.cs',
    'src/App/Migrations/CoreDbContextModelSnapshot.cs',
  ];

  it('is empty when every reference migration is present on disk', () => {
    const present = [
      'src/App/Migrations/core_v3_54_0_001_InitialCreate.cs',
      'src/App/Migrations/core_v3_54_0_002_AddInvoices.cs',
      'src/App/Migrations/core_v3_54_0_003_BranchOnlyThing.cs', // extra local = fine
    ];
    expect(findMissingReferenceMigrations(ref, present)).toEqual([]);
  });

  it('flags a reference migration deleted from the working tree (the incident)', () => {
    // working tree dropped v3_54_0_001 (which lives on origin/main) — casse-prod
    const present = ['src/App/Migrations/core_v3_54_0_002_AddInvoices.cs'];
    expect(findMissingReferenceMigrations(ref, present)).toEqual([
      'core_v3_54_0_001_InitialCreate',
    ]);
  });

  it('flags a renamed reference migration (the manual re-baseline)', () => {
    // v3_54_0_001 renamed to v3_55_0_001 locally → the original key is now missing
    const present = [
      'src/App/Migrations/core_v3_55_0_001_InitialCreate.cs',
      'src/App/Migrations/core_v3_54_0_002_AddInvoices.cs',
    ];
    expect(findMissingReferenceMigrations(ref, present)).toEqual([
      'core_v3_54_0_001_InitialCreate',
    ]);
  });

  it('reports every missing reference migration, sorted + de-duplicated', () => {
    expect(findMissingReferenceMigrations(ref, [])).toEqual([
      'core_v3_54_0_001_InitialCreate',
      'core_v3_54_0_002_AddInvoices',
    ]);
  });

  it('matches across path-separator and .Designer noise', () => {
    const present = ['src\\App\\Migrations\\core_v3_54_0_001_InitialCreate.Designer.cs'];
    // only the InitialCreate is satisfied (via its designer); AddInvoices missing
    expect(findMissingReferenceMigrations(ref, present)).toEqual([
      'core_v3_54_0_002_AddInvoices',
    ]);
  });

  it('is empty for an empty reference set', () => {
    expect(findMissingReferenceMigrations([], ['anything.cs'])).toEqual([]);
  });
});

describe('referenceMigrationNames — the 🔒 parent list', () => {
  it('returns sorted unique migration names, excluding snapshot + designers', () => {
    const ref = [
      'src/App/Migrations/core_v1_0_0_002_AddOrders.cs',
      'src/App/Migrations/core_v1_0_0_002_AddOrders.Designer.cs',
      'src/App/Migrations/core_v1_0_0_001_InitialCreate.cs',
      'src/App/Migrations/CoreDbContextModelSnapshot.cs',
    ];
    expect(referenceMigrationNames(ref)).toEqual([
      'core_v1_0_0_001_InitialCreate',
      'core_v1_0_0_002_AddOrders',
    ]);
  });
  it('is empty for no reference files', () => {
    expect(referenceMigrationNames([])).toEqual([]);
  });
});
