import { Password } from "@/contexts/common/domain";
import {
  AggregateRoot,
  Email,
  IDomainError,
  Language,
  Name,
  Result,
  UniqueID,
} from "@shared/contexts";
import { AuthUserRole } from "./AuthUserRole";

export interface IAuthUserProps {
  name: Name;
  email: Email;
  password: Password;
  language: Language;
  roles: AuthUserRole[];
}

export interface IAuthUser {
  id: UniqueID;
  name: Name;
  email: Email;
  password: Password;
  language: Language;
  isUser: boolean;
  isAdmin: boolean;
  getRoles: () => AuthUserRole[];
  getRolesArray: () => string[];

  verifyPassword: (candidatePassword: string) => boolean;
}

export class AuthUser extends AggregateRoot<IAuthUserProps> implements IAuthUser {
  public static create(props: IAuthUserProps, id?: UniqueID): Result<AuthUser, IDomainError> {
    const user = new AuthUser(props, id);
    return Result.ok<AuthUser>(user);
  }

  public static async hashPassword(password): Promise<string> {
    return Password.hashPassword(password);
  }

  private roles: AuthUserRole[];

  constructor(props: IAuthUserProps, id?: UniqueID) {
    const { roles } = props;
    super(props, id);
    this.roles = roles;
  }

  get name(): Name {
    return this.props.name;
  }

  get email(): Email {
    return this.props.email;
  }

  get password(): Password {
    return this.props.password;
  }

  get language(): Language {
    return this.props.language;
  }

  get isUser(): boolean {
    return this._hasRole(AuthUserRole.ROLE_USER);
  }

  get isAdmin(): boolean {
    return this._hasRole(AuthUserRole.ROLE_ADMIN);
  }

  public getRoles(): AuthUserRole[] {
    return this.roles;
  }

  public getRolesArray(): string[] {
    return this.getRoles()?.map((rol) => rol.toString());
  }

  public verifyPassword(candidatePassword: string): boolean {
    return this.props.password.verifyPassword(candidatePassword);
  }

  private _hasRole(role: AuthUserRole): boolean {
    return (this.roles || []).some((r) => r.equals(role));
  }
}
