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

import { User } from '@core/identity/domain/entities/User';

import { UserOrmEntity } from '../entities/UserOrmEntity';
import { TypeOrmIdentitySchemaError } from '../errors/TypeOrmIdentitySchemaError';
import { UserOrmMapper } from './UserOrmMapper';

describe('UserOrmMapper', () => {
  it('toDomain preserves persisted identity and uses rehydrate semantics (does not call create)', () => {
    const mapper = new UserOrmMapper();

    const entity = new UserOrmEntity();
    entity.id = '00000000-0000-4000-8000-000000000001';
    entity.email = 'alice@example.com';
    entity.displayName = 'Alice';
    entity.passwordHash = 'bcrypt-hash';
    entity.salt = 'test-salt';
    entity.primaryDriverId = null;
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');

    if (typeof (User as unknown as { rehydrate?: unknown }).rehydrate !== 'function') {
      throw new Error('rehydrate-missing');
    }

    const rehydrateSpy = vi.spyOn(User as unknown as { rehydrate: (...args: unknown[]) => unknown }, 'rehydrate');
    const createSpy = vi.spyOn(User, 'create').mockImplementation(() => {
      throw new Error('create-called');
    });

    const domain = mapper.toDomain(entity);

    expect(domain.getId().value).toBe(entity.id);
    expect(domain.getEmail()).toBe(entity.email);

    expect(createSpy).not.toHaveBeenCalled();
    expect(rehydrateSpy).toHaveBeenCalled();
  });

  it('toDomain validates persisted shape and throws adapter-scoped base schema error type', () => {
    const mapper = new UserOrmMapper();

    const entity = new UserOrmEntity();
    entity.id = '00000000-0000-4000-8000-000000000001';
    entity.email = 123 as unknown as string;
    entity.displayName = 'Alice';
    entity.passwordHash = 'bcrypt-hash';
    entity.salt = 'test-salt';
    entity.primaryDriverId = null;
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');

    try {
      mapper.toDomain(entity);
      throw new Error('expected-to-throw');
    } catch (error) {
      expect(error).toBeInstanceOf(TypeOrmIdentitySchemaError);
      expect(error).toMatchObject({
        entityName: 'User',
        fieldName: 'email',
        reason: 'not_string',
      });
    }
  });
});