import { Result } from "@repo/rdx-utils";

import { AggregateRoot, EmailAddress, UniqueID } from "@/core/common/domain";
import { UserAuthenticatedEvent } from "../events";
import { HashPassword, PlainPassword, Username } from "../value-objects";

export interface IAuthenticatedUserProps {
  username: Username;
  email: EmailAddress;
  hashPassword: HashPassword;
  roles: string[];
}

export interface IAuthenticatedUser {
  username: Username;
  email: EmailAddress;
  hashPassword: HashPassword;

  accessToken: string;
  refreshToken: string;

  isUser: boolean;
  isAdmin: boolean;

  verifyPassword(candidatePassword: PlainPassword): Promise<boolean>;
  hasRole(role: string): boolean;
  hasRoles(roles: string[]): boolean;
  getRoles(): string[];
  toPersistenceData(): any;
}

export class AuthenticatedUser
  extends AggregateRoot<IAuthenticatedUserProps>
  implements IAuthenticatedUser
{
  public accessToken = "";
  public refreshToken = "";

  static create(props: IAuthenticatedUserProps, id: UniqueID): Result<AuthenticatedUser, Error> {
    const user = new AuthenticatedUser(props, id);

    // 🔹 Disparar evento de dominio "UserAuthenticatedEvent"
    const { email } = props;
    user.addDomainEvent(new UserAuthenticatedEvent(id, email.toString()));

    return Result.ok(user);
  }

  verifyPassword(candidatePassword: PlainPassword): Promise<boolean> {
    return this.props.hashPassword.verifyPassword(candidatePassword.toString());
  }

  getRoles(): string[] {
    return this.props.roles;
  }

  hasRole(role: string): boolean {
    return (this.props.roles || []).some((r) => r === role);
  }

  hasRoles(roles: string[]): boolean {
    return roles && roles.map((rol) => this.hasRole(rol)).some((value) => value != false);
  }

  get username(): Username {
    return this.props.username;
  }

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

  get hashPassword(): HashPassword {
    return this.props.hashPassword;
  }

  get isUser(): boolean {
    return this.hasRole("user");
  }

  get isAdmin(): boolean {
    return this.hasRole("admin");
  }

  /**
   * 🔹 Devuelve una representación lista para persistencia
   */
  toPersistenceData(): any {
    return;
  }
}
