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

import { Team } from '@core/racing/domain/entities/Team';

import { TeamMembershipOrmEntity, TeamOrmEntity } from '../entities/TeamOrmEntities';
import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';
import { TeamMembershipOrmMapper, TeamOrmMapper } from './TeamOrmMappers';

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

    const entity = new TeamOrmEntity();
    entity.id = '00000000-0000-4000-8000-000000000001';
    entity.name = 'Team One';
    entity.tag = 'T1';
    entity.description = 'Desc';
    entity.ownerId = '00000000-0000-4000-8000-000000000002';
    entity.leagues = ['00000000-0000-4000-8000-000000000003'];
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');

    const rehydrateSpy = vi.spyOn(Team, 'rehydrate');
    const createSpy = vi.spyOn(Team, 'create').mockImplementation(() => {
      throw new Error('create-called');
    });

    const domain = mapper.toDomain(entity);

    expect(domain.id).toBe(entity.id);
    expect(domain.ownerId.toString()).toBe(entity.ownerId);
    expect(createSpy).not.toHaveBeenCalled();
    expect(rehydrateSpy).toHaveBeenCalled();
  });

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

    const entity = new TeamOrmEntity();
    entity.id = '';
    entity.name = 'Team One';
    entity.tag = 'T1';
    entity.description = 'Desc';
    entity.ownerId = '00000000-0000-4000-8000-000000000002';
    entity.leagues = [];
    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(TypeOrmPersistenceSchemaError);
      expect(error).toMatchObject({
        entityName: 'Team',
        fieldName: 'id',
        reason: 'empty_string',
      });
    }
  });
});

describe('TeamMembershipOrmMapper', () => {
  it('toDomainMembership validates enum role/status and throws adapter-scoped base schema error type', () => {
    const mapper = new TeamMembershipOrmMapper();

    const entity = new TeamMembershipOrmEntity();
    entity.teamId = '00000000-0000-4000-8000-000000000001';
    entity.driverId = '00000000-0000-4000-8000-000000000002';
    entity.role = 'invalid';
    entity.status = 'active';
    entity.joinedAt = new Date('2025-01-01T00:00:00.000Z');

    try {
      mapper.toDomainMembership(entity);
      throw new Error('expected-to-throw');
    } catch (error) {
      expect(error).toBeInstanceOf(TypeOrmPersistenceSchemaError);
      expect(error).toMatchObject({
        entityName: 'TeamMembership',
        fieldName: 'role',
        reason: 'invalid_enum_value',
      });
    }
  });

  it('round-trips membership toOrmMembership <-> toDomainMembership', () => {
    const mapper = new TeamMembershipOrmMapper();

    const domain = {
      teamId: '00000000-0000-4000-8000-000000000001',
      driverId: '00000000-0000-4000-8000-000000000002',
      role: 'driver' as const,
      status: 'active' as const,
      joinedAt: new Date('2025-01-01T00:00:00.000Z'),
    };

    const orm = mapper.toOrmMembership(domain);
    const rehydrated = mapper.toDomainMembership(orm);

    expect(rehydrated).toEqual(domain);
  });
});