import type { ObjectLiteral } from 'typeorm';
import type { Queue, Job } from 'bullmq';
import type { Mock } from 'vitest';

/**
 * Mock repository type for services using @InjectRepository().
 */
export interface MockRepository<_T extends ObjectLiteral = ObjectLiteral> {
  find: Mock;
  findOne: Mock;
  findOneBy: Mock;
  save: Mock;
  create: Mock;
  update: Mock;
  delete: Mock;
  remove: Mock;
  count: Mock;
  createQueryBuilder: Mock;
}

/**
 * Creates a mock TypeORM repository.
 */
export function createMockRepository<T extends ObjectLiteral>(): MockRepository<T> {
  return {
    find: vi.fn(),
    findOne: vi.fn(),
    findOneBy: vi.fn(),
    save: vi.fn(),
    create: vi.fn(),
    update: vi.fn(),
    delete: vi.fn(),
    remove: vi.fn(),
    count: vi.fn(),
    createQueryBuilder: vi.fn(),
  };
}

/**
 * Mock BullMQ Queue for services using @InjectQueue().
 */
export interface MockQueue {
  add: Mock;
  remove: Mock;
  getJob: Mock;
  getJobs: Mock;
  clean: Mock;
  obliterate: Mock;
  pause: Mock;
  resume: Mock;
  isPaused: Mock;
}

/**
 * Creates a mock BullMQ Queue.
 */
export function createMockQueue(): MockQueue {
  return {
    add: vi.fn().mockResolvedValue({ id: 'mock-job-id' } as Job),
    remove: vi.fn().mockResolvedValue(undefined),
    getJob: vi.fn().mockResolvedValue(null),
    getJobs: vi.fn().mockResolvedValue([]),
    clean: vi.fn().mockResolvedValue([]),
    obliterate: vi.fn().mockResolvedValue(undefined),
    pause: vi.fn().mockResolvedValue(undefined),
    resume: vi.fn().mockResolvedValue(undefined),
    isPaused: vi.fn().mockResolvedValue(false),
  };
}

/**
 * Mock Express Request for controller testing.
 */
export interface MockRequest {
  headers: Record<string, string | string[] | undefined>;
  socket: {
    remoteAddress?: string;
  };
}

/**
 * Creates a mock Express request.
 */
export function createMockRequest(overrides: Partial<MockRequest> = {}): MockRequest {
  return {
    headers: {},
    socket: {},
    ...overrides,
  };
}
