import { describe, expect, it, vi } from 'vitest';
import * as fs from 'node:fs';
import * as path from 'node:path';

import { TypeOrmAvatarGenerationRepository } from './TypeOrmAvatarGenerationRepository';

describe('TypeOrmAvatarGenerationRepository', () => {
  it('does not construct its own mapper dependencies', () => {
    const sourcePath = path.resolve(__dirname, 'TypeOrmAvatarGenerationRepository.ts');
    const source = fs.readFileSync(sourcePath, 'utf8');

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

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

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

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

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

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

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

    // Test findByUserId
    const requests = await repo.findByUserId('user-1');
    expect(ormRepo.find).toHaveBeenCalledWith({ 
      where: { userId: 'user-1' },
      order: { createdAt: 'DESC' }
    });
    expect(mapper.toDomain).toHaveBeenCalledTimes(3); // 1 from findById + 2 from findByUserId
    expect(requests).toHaveLength(2);

    // Test findLatestByUserId
    await repo.findLatestByUserId('user-1');
    expect(ormRepo.findOne).toHaveBeenCalledWith({
      where: { userId: 'user-1' },
      order: { createdAt: 'DESC' }
    });

    // Test save
    const domainRequest = { id: 'new-request', toProps: () => ({ id: 'new-request' }) };
    await repo.save(domainRequest as any);
    expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainRequest);
    expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-request-1' });

    // Test delete
    await repo.delete('request-1');
    expect(ormRepo.delete).toHaveBeenCalledWith({ id: 'request-1' });
  });
});
