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

import { Media } from '@core/media/domain/entities/Media';

import { MediaOrmEntity } from '../entities/MediaOrmEntity';
import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError';
import { MediaOrmMapper } from './MediaOrmMapper';

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

    const entity = new MediaOrmEntity();
    entity.id = '00000000-0000-4000-8000-000000000001';
    entity.filename = 'test-image.png';
    entity.originalName = 'original.png';
    entity.mimeType = 'image/png';
    entity.size = 12345;
    entity.url = 'https://cdn.example.com/test-image.png';
    entity.type = 'image';
    entity.uploadedBy = 'user-123';
    entity.uploadedAt = new Date('2025-01-01T00:00:00.000Z');
    entity.metadata = { width: 800, height: 600 };

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

    const reconstituteSpy = vi.spyOn(Media as unknown as { reconstitute: (...args: unknown[]) => unknown }, 'reconstitute');

    const domain = mapper.toDomain(entity);

    expect(domain.id).toBe(entity.id);
    expect(domain.filename).toBe(entity.filename);
    expect(domain.url.value).toBe(entity.url);

    expect(reconstituteSpy).toHaveBeenCalled();
  });

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

    const entity = new MediaOrmEntity();
    entity.id = '00000000-0000-4000-8000-000000000001';
    entity.filename = 123 as unknown as string;
    entity.originalName = 'original.png';
    entity.mimeType = 'image/png';
    entity.size = 12345;
    entity.url = 'https://cdn.example.com/test-image.png';
    entity.type = 'image';
    entity.uploadedBy = 'user-123';
    entity.uploadedAt = new Date('2025-01-01T00:00:00.000Z');
    entity.metadata = null;

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

  it('toOrmEntity converts domain entity to ORM entity', () => {
    const mapper = new MediaOrmMapper();

    const domain = Media.create({
      id: '00000000-0000-4000-8000-000000000001',
      filename: 'test-image.png',
      originalName: 'original.png',
      mimeType: 'image/png',
      size: 12345,
      url: 'https://cdn.example.com/test-image.png',
      type: 'image',
      uploadedBy: 'user-123',
      metadata: { width: 800, height: 600 },
    });

    const entity = mapper.toOrmEntity(domain);

    expect(entity.id).toBe(domain.id);
    expect(entity.filename).toBe(domain.filename);
    expect(entity.url).toBe(domain.url.value);
    expect(entity.metadata).toEqual({ width: 800, height: 600 });
  });

  it('toDomain handles null metadata', () => {
    const mapper = new MediaOrmMapper();

    const entity = new MediaOrmEntity();
    entity.id = '00000000-0000-4000-8000-000000000001';
    entity.filename = 'test-image.png';
    entity.originalName = 'original.png';
    entity.mimeType = 'image/png';
    entity.size = 12345;
    entity.url = 'https://cdn.example.com/test-image.png';
    entity.type = 'image';
    entity.uploadedBy = 'user-123';
    entity.uploadedAt = new Date('2025-01-01T00:00:00.000Z');
    entity.metadata = null;

    const domain = mapper.toDomain(entity);

    expect(domain.id).toBe(entity.id);
    expect(domain.metadata).toBeUndefined();
  });
});
