import { Password } from "@/contexts/common/domain";
import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
import { UserRole } from "@/contexts/users/domain";
import { Email, Language, Name, UniqueID } from "@shared/contexts";
import { AuthUser, IAuthUserProps } from "../../domain/entities";
import { IAuthContext } from "../Auth.context";
import { AuthUserCreationAttributes, AuthUser_Model } from "../sequelize/authUser.model";

export interface IUserMapper
  extends ISequelizeMapper<AuthUser_Model, AuthUserCreationAttributes, AuthUser> {}

class AuthUserMapper
  extends SequelizeMapper<AuthUser_Model, AuthUserCreationAttributes, AuthUser>
  implements IUserMapper
{
  protected toDomainMappingImpl(source: AuthUser_Model, params: any): AuthUser {
    const props: IAuthUserProps = {
      name: this.mapsValue(source, "name", Name.create),
      email: this.mapsValue(source, "email", Email.create),
      password: this.mapsValue(source, "password", Password.createFromHashedTextPassword),
      language: this.mapsValue(source, "lang_code", Language.createFromCode, {
        defaultValue: Language.DEFAULT_LANGUAGE_CODE,
      }),
      roles: source.roles.map((rol) => UserRole.create(rol).object),
    };

    const id = this.mapsValue(source, "id", UniqueID.create);
    const userOrError = AuthUser.create(props, id);

    if (userOrError.isFailure) {
      throw userOrError.error;
    }

    return userOrError.object;
  }

  protected toPersistenceMappingImpl(source: AuthUser, params?: Record<string, any> | undefined) {
    return {
      id: source.id.toPrimitive(),
      name: source.name.toPrimitive(),
      email: source.email.toPrimitive(),
      password: source.password.toPrimitive(),
      lang_code: source.language.toPrimitive(),
      roles: source.getRoles().map((role) => role.toPrimitive()),
    };
  }
}

export const createUserMapper = (context: IAuthContext): IUserMapper =>
  new AuthUserMapper({
    context,
  });
