import {
  AggregateRoot,
  type EmailAddress,
  type PhoneNumber,
  PostalAddress,
  type TINNumber,
  UniqueID,
} from "@/core";
import { Maybe, Result } from "@repo/rdx-utils";
import { AccountStatus } from "../value-objects";

export interface IAccountProps {
  status: AccountStatus;

  isFreelancer: boolean;
  name: string;
  tin: TINNumber;
  address: PostalAddress;
  email: EmailAddress;
  phone: PhoneNumber;
  legalRecord: string;
  defaultTax: number;

  langCode: string;
  currencyCode: string;

  tradeName: Maybe<string>;
  website: Maybe<string>;
  fax: Maybe<PhoneNumber>;
  logo: Maybe<string>;
}

export interface IAccount {
  id: UniqueID;
  status: AccountStatus;
  name: string;
  tin: TINNumber;
  address: PostalAddress;
  email: EmailAddress;
  phone: PhoneNumber;
  legalRecord: string;
  defaultTax: number;

  langCode: string;
  currencyCode: string;

  tradeName: Maybe<string>;
  fax: Maybe<PhoneNumber>;
  website: Maybe<string>;
  logo: Maybe<string>;

  isAccount: boolean;
  isFreelancer: boolean;
  isActive: boolean;

  activate(): boolean;
  deactivate(): boolean;
}

export class Account extends AggregateRoot<IAccountProps> implements IAccount {
  id: UniqueID;
  static create(props: IAccountProps, id?: UniqueID): Result<Account, Error> {
    const account = new Account(props, id);

    // Reglas de negocio / validaciones
    // ...
    // ...

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

    return Result.ok(account);
  }

  static update(oldAccount: Account, data: Partial<IAccountProps>): Result<Account, Error> {
    const updatedPostalAddress = PostalAddress.update(oldAccount.address, data.address ?? {}).data;

    return Account.create(
      {
        isFreelancer: data.isFreelancer ?? oldAccount.isFreelancer,

        name: data.name ?? oldAccount.name,
        tin: data.tin ?? oldAccount.tin,

        address: updatedPostalAddress,
        email: data.email ?? oldAccount.email,
        phone: data.phone ?? oldAccount.phone,

        legalRecord: data.legalRecord ?? oldAccount.legalRecord,
        defaultTax: data.defaultTax ?? oldAccount.defaultTax,
        status: oldAccount.props.status,
        langCode: data.langCode ?? oldAccount.langCode,
        currencyCode: data.currencyCode ?? oldAccount.currencyCode,

        tradeName: data.tradeName ?? oldAccount.tradeName,
        website: data.website ?? oldAccount.website,
        fax: data.fax ?? oldAccount.fax,
        logo: data.logo ?? oldAccount.logo,
      },
      oldAccount.id
    ).getOrElse(this);
  }

  activate() {
    if (!this.props.status.canTransitionTo("active")) {
      return false;
    }
    this.props.status = AccountStatus.createActive();
    return true;
  }

  deactivate() {
    if (!this.props.status.canTransitionTo("inactive")) {
      return false;
    }
    this.props.status = AccountStatus.createInactive();
    return true;
  }

  get status() {
    return this.props.status;
  }

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

  get tradeName() {
    return this.props.tradeName;
  }

  get tin(): TINNumber {
    return this.props.tin;
  }

  get address(): PostalAddress {
    return this.props.address;
  }

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

  get phone(): PhoneNumber {
    return this.props.phone;
  }

  get fax(): Maybe<PhoneNumber> {
    return this.props.fax;
  }

  get website() {
    return this.props.website;
  }

  get legalRecord() {
    return this.props.legalRecord;
  }

  get defaultTax() {
    return this.props.defaultTax;
  }

  get langCode() {
    return this.props.langCode;
  }

  get currencyCode() {
    return this.props.currencyCode;
  }

  get logo() {
    return this.props.logo;
  }

  get isAccount(): boolean {
    return !this.props.isFreelancer;
  }

  get isFreelancer(): boolean {
    return this.props.isFreelancer;
  }

  get isActive(): boolean {
    return this.props.status.equals(AccountStatus.createActive());
  }
}
