import { describe, expect, it, vi } from 'vitest';

import { TypeOrmNotificationPreferenceRepository } from './TypeOrmNotificationPreferenceRepository';

describe('TypeOrmNotificationPreferenceRepository', () => {
  it('does not construct its own mapper dependencies', () => {
    // Check that the repository doesn't create its own mapper
    const sourcePath = require.resolve('./TypeOrmNotificationPreferenceRepository.ts');
    const fs = require('fs');
    const source = fs.readFileSync(sourcePath, 'utf8');

    expect(source).not.toMatch(/new\s+NotificationPreferenceOrmMapper\s*\(/);
    expect(source).not.toMatch(/=\s*new\s+NotificationPreferenceOrmMapper\s*\(/);
  });

  it('requires mapper injection via constructor (no default mapper)', () => {
    expect(TypeOrmNotificationPreferenceRepository.length).toBe(2);
  });

  it('uses the injected mapper at runtime (DB-free)', async () => {
    const ormRepo = {
      findOne: vi.fn().mockResolvedValue({ id: 'driver-123' }),
      save: vi.fn().mockResolvedValue({ id: 'driver-123' }),
      delete: vi.fn().mockResolvedValue({ affected: 1 }),
    };

    const dataSource = {
      getRepository: vi.fn().mockReturnValue(ormRepo),
    };

    const mapper = {
      toDomain: vi.fn().mockReturnValue({ id: 'domain-preference-1' }),
      toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-preference-1' }),
    };

    const repo = new TypeOrmNotificationPreferenceRepository(dataSource as any, mapper as any);

    // Test findByDriverId
    const preference = await repo.findByDriverId('driver-123');
    expect(dataSource.getRepository).toHaveBeenCalledTimes(1);
    expect(ormRepo.findOne).toHaveBeenCalledWith({ where: { driverId: 'driver-123' } });
    expect(mapper.toDomain).toHaveBeenCalledTimes(1);
    expect(preference).toEqual({ id: 'domain-preference-1' });

    // Test save
    const domainPreference = { id: 'driver-123', driverId: 'driver-123', toJSON: () => ({ id: 'driver-123', driverId: 'driver-123' }) };
    await repo.save(domainPreference as any);
    expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainPreference);
    expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-preference-1' });

    // Test delete
    await repo.delete('driver-123');
    expect(ormRepo.delete).toHaveBeenCalledWith({ driverId: 'driver-123' });

    // Test getOrCreateDefault - existing
    ormRepo.findOne.mockResolvedValue({ id: 'existing' });
    const existing = await repo.getOrCreateDefault('driver-123');
    expect(existing).toEqual({ id: 'domain-preference-1' });
    expect(ormRepo.save).toHaveBeenCalledTimes(1); // Only from previous save test

    // Test getOrCreateDefault - new
    ormRepo.findOne.mockResolvedValue(null);
    
    // The getOrCreateDefault should create default preferences and save them
    await repo.getOrCreateDefault('driver-456');
    expect(ormRepo.findOne).toHaveBeenCalledWith({ where: { driverId: 'driver-456' } });
    expect(ormRepo.save).toHaveBeenCalled(); // Should save the new default preferences
  });
});