import { ValueObject } from "core/common/domain";
import { Result } from "core/common/helpers";

interface IInvoiceStatusProps {
  value: string;
}

export enum INVOICE_STATUS {
  DRAFT = "draft",
  EMITTED = "emitted",
  SENT = "sent",
  REJECTED = "rejected",
}
export class InvoiceStatus extends ValueObject<IInvoiceStatusProps> {
  private static readonly ALLOWED_STATUSES = ["draft", "emitted", "sent", "rejected"];

  private static readonly TRANSITIONS: Record<string, string[]> = {
    draft: [INVOICE_STATUS.EMITTED],
    emitted: [INVOICE_STATUS.SENT, INVOICE_STATUS.REJECTED, INVOICE_STATUS.DRAFT],
    sent: [INVOICE_STATUS.REJECTED],
    rejected: [],
  };

  static create(value: string): Result<InvoiceStatus, Error> {
    if (!this.ALLOWED_STATUSES.includes(value)) {
      return Result.fail(new Error(`Estado de la factura no válido: ${value}`));
    }

    return Result.ok(
      value === "rejected"
        ? InvoiceStatus.createRejected()
        : value === "sent"
          ? InvoiceStatus.createSent()
          : value === "emitted"
            ? InvoiceStatus.createSent()
            : InvoiceStatus.createDraft()
    );
  }

  public static createDraft(): InvoiceStatus {
    return new InvoiceStatus({ value: INVOICE_STATUS.DRAFT });
  }

  public static createEmitted(): InvoiceStatus {
    return new InvoiceStatus({ value: INVOICE_STATUS.EMITTED });
  }

  public static createSent(): InvoiceStatus {
    return new InvoiceStatus({ value: INVOICE_STATUS.SENT });
  }

  public static createRejected(): InvoiceStatus {
    return new InvoiceStatus({ value: INVOICE_STATUS.REJECTED });
  }

  getValue(): string {
    return this.props.value;
  }

  toPrimitive() {
    return this.getValue();
  }

  canTransitionTo(nextStatus: string): boolean {
    return InvoiceStatus.TRANSITIONS[this.props.value].includes(nextStatus);
  }

  transitionTo(nextStatus: string): Result<InvoiceStatus, Error> {
    if (!this.canTransitionTo(nextStatus)) {
      return Result.fail(
        new Error(`Transición no permitida de ${this.props.value} a ${nextStatus}`)
      );
    }
    return InvoiceStatus.create(nextStatus);
  }

  toString(): string {
    return this.getValue();
  }
}
