import { User } from '@core/identity/domain/entities/User';
import type { StoredUser } from '@core/identity/domain/repositories/IUserRepository';
import { PasswordHash } from '@core/identity/domain/value-objects/PasswordHash';

import { UserOrmEntity } from '../entities/UserOrmEntity';
import { TypeOrmIdentitySchemaError } from '../errors/TypeOrmIdentitySchemaError';
import { assertDate, assertNonEmptyString, assertOptionalStringOrNull } from '../schema/TypeOrmIdentitySchemaGuards';

export class UserOrmMapper {
  toDomain(entity: UserOrmEntity): User {
    const entityName = 'User';

    try {
      assertNonEmptyString(entityName, 'id', entity.id);
      assertNonEmptyString(entityName, 'email', entity.email);
      assertNonEmptyString(entityName, 'displayName', entity.displayName);
      assertNonEmptyString(entityName, 'passwordHash', entity.passwordHash);
      assertNonEmptyString(entityName, 'salt', entity.salt);
      assertOptionalStringOrNull(entityName, 'primaryDriverId', entity.primaryDriverId);
      assertDate(entityName, 'createdAt', entity.createdAt);
    } catch (error) {
      if (error instanceof TypeOrmIdentitySchemaError) {
        throw error;
      }
      const message = error instanceof Error ? error.message : 'Invalid persisted User';
      throw new TypeOrmIdentitySchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
    }

    try {
      const passwordHash = entity.passwordHash ? PasswordHash.fromHash(entity.passwordHash) : undefined;

      return User.rehydrate({
        id: entity.id,
        email: entity.email,
        displayName: entity.displayName,
        ...(passwordHash ? { passwordHash } : {}),
        ...(entity.primaryDriverId ? { primaryDriverId: entity.primaryDriverId } : {}),
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Invalid persisted User';
      throw new TypeOrmIdentitySchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
    }
  }

  toOrmEntity(stored: StoredUser): UserOrmEntity {
    const entity = new UserOrmEntity();
    entity.id = stored.id;
    entity.email = stored.email;
    entity.displayName = stored.displayName;
    entity.passwordHash = stored.passwordHash;
    entity.salt = stored.salt;
    entity.primaryDriverId = stored.primaryDriverId ?? null;
    entity.createdAt = stored.createdAt;
    return entity;
  }

  toStored(entity: UserOrmEntity): StoredUser {
    return {
      id: entity.id,
      email: entity.email,
      displayName: entity.displayName,
      passwordHash: entity.passwordHash,
      salt: entity.salt,
      primaryDriverId: entity.primaryDriverId ?? undefined,
      createdAt: entity.createdAt,
    };
  }
}