import {
  AggregateRoot,
  CurrencyCode,
  EmailAddress,
  LanguageCode,
  Name,
  PhoneNumber,
  PostalAddress,
  PostalAddressPatchProps,
  TINNumber,
  TaxCode,
  TextValue,
  URLAddress,
  UniqueID,
} from "@repo/rdx-ddd";
import { Collection, Maybe, Result } from "@repo/rdx-utils";
import { CustomerStatus } from "../value-objects";

export interface CustomerProps {
  companyId: UniqueID;
  status: CustomerStatus;
  reference: Maybe<Name>;

  isCompany: boolean;
  name: Name;
  tradeName: Maybe<Name>;
  tin: Maybe<TINNumber>;

  address: PostalAddress;

  emailPrimary: Maybe<EmailAddress>;
  emailSecondary: Maybe<EmailAddress>;

  phonePrimary: Maybe<PhoneNumber>;
  phoneSecondary: Maybe<PhoneNumber>;

  mobilePrimary: Maybe<PhoneNumber>;
  mobileSecondary: Maybe<PhoneNumber>;

  fax: Maybe<PhoneNumber>;
  website: Maybe<URLAddress>;

  legalRecord: Maybe<TextValue>;

  defaultTaxes: Collection<TaxCode>;

  languageCode: LanguageCode;
  currencyCode: CurrencyCode;
}

export type CustomerPatchProps = Partial<Omit<CustomerProps, "companyId" | "address">> & {
  address?: PostalAddressPatchProps;
};

// Customer
export interface ICustomer {
  // comportamiento
  update(partialCustomer: CustomerPatchProps): Result<Customer, Error>;

  // propiedades (getters)
  readonly isIndividual: boolean;
  readonly isCompany: boolean;
  readonly isActive: boolean;

  readonly companyId: UniqueID;

  readonly reference: Maybe<Name>;
  readonly name: Name;
  readonly tradeName: Maybe<Name>;
  readonly tin: Maybe<TINNumber>;

  readonly address: PostalAddress;

  readonly emailPrimary: Maybe<EmailAddress>;
  readonly emailSecondary: Maybe<EmailAddress>;

  readonly phonePrimary: Maybe<PhoneNumber>;
  readonly phoneSecondary: Maybe<PhoneNumber>;
  readonly mobilePrimary: Maybe<PhoneNumber>;
  readonly mobileSecondary: Maybe<PhoneNumber>;
  readonly fax: Maybe<PhoneNumber>;

  readonly website: Maybe<URLAddress>;
  readonly legalRecord: Maybe<TextValue>;

  readonly defaultTaxes: Collection<TaxCode>;

  readonly languageCode: LanguageCode;
  readonly currencyCode: CurrencyCode;
}

export class Customer extends AggregateRoot<CustomerProps> implements ICustomer {
  static create(props: CustomerProps, id?: UniqueID): Result<Customer, Error> {
    const contact = new Customer(props, id);

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

    // Disparar eventos de dominio
    // ...
    // ...

    return Result.ok(contact);
  }

  public update(partialCustomer: CustomerPatchProps): Result<Customer, Error> {
    const { address: partialAddress, ...rest } = partialCustomer;
    const updatedProps = {
      ...this.props,
      ...rest,
    } as CustomerProps;

    if (partialAddress) {
      const updatedAddressOrError = this.address.update(partialAddress);
      if (updatedAddressOrError.isFailure) {
        return Result.fail(updatedAddressOrError.error);
      }

      updatedProps.address = updatedAddressOrError.data;
    }

    return Customer.create(updatedProps, this.id);
  }

  public get isIndividual(): boolean {
    return !this.props.isCompany;
  }

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

  public get isActive(): boolean {
    return this.props.status.isActive();
  }

  public get companyId(): UniqueID {
    return this.props.companyId;
  }

  public get reference(): Maybe<Name> {
    return this.props.reference;
  }

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

  public get tradeName(): Maybe<Name> {
    return this.props.tradeName;
  }

  public get tin(): Maybe<TINNumber> {
    return this.props.tin;
  }

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

  public get emailPrimary(): Maybe<EmailAddress> {
    return this.props.emailPrimary;
  }

  public get emailSecondary(): Maybe<EmailAddress> {
    return this.props.emailSecondary;
  }

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

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

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

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

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

  public get website(): Maybe<URLAddress> {
    return this.props.website;
  }

  public get legalRecord(): Maybe<TextValue> {
    return this.props.legalRecord;
  }

  public get defaultTaxes(): Collection<TaxCode> {
    return this.props.defaultTaxes;
  }

  public get languageCode(): LanguageCode {
    return this.props.languageCode;
  }

  public get currencyCode(): CurrencyCode {
    return this.props.currencyCode;
  }
}
