import type { UniqueID } from "@repo/rdx-ddd"; import { AggregateRoot } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { z } from "zod/v4"; import { CertificateConfigurationRevision } from "./certificate-configuration-revision.entity"; import { CERTIFICATE_STATE_TRANSITIONS, CertificateConfigurationError, } from "./certificate-configuration-values"; import type { CertificateConfigurationValues } from "./value-objects/certificate-configuration-values"; type Props = Readonly<{ companyId: UniqueID; values: CertificateConfigurationValues; history: readonly CertificateConfigurationRevision[]; }>; export class CertificateConfiguration extends AggregateRoot { private constructor(props: Props, id?: UniqueID) { super(Object.freeze({ ...props, history: Object.freeze([...props.history]) }), id); } static create( companyId: UniqueID, values: CertificateConfigurationValues, actorId: UniqueID, recordedAt: string ): Result { if ( !( z.iso.datetime().safeParse(recordedAt).success && ["pending", "configured"].includes(values.state) ) ) { return Result.fail(new CertificateConfigurationError("INVALID_CERTIFICATE_TRANSITION")); } return Result.ok( new CertificateConfiguration({ companyId, values, history: [CertificateConfigurationRevision.create({ values, actorId, recordedAt })], }) ); } static rehydrate(props: Props, id: UniqueID) { return new CertificateConfiguration(props, id); } get companyId() { return this.props.companyId; } get values() { return this.props.values; } get history() { return this.props.history; } update( values: CertificateConfigurationValues, actorId: UniqueID, recordedAt: string ): Result { if (this.values.equals(values)) { return Result.ok(this); } if (!this.values.sameTarget(values)) { return Result.fail(new CertificateConfigurationError("CERTIFICATE_TARGET_IMMUTABLE")); } if ( !CERTIFICATE_STATE_TRANSITIONS[this.values.state].some((state) => state === values.state) || (this.values.closed && !this.values.equals(values)) ) { return Result.fail(new CertificateConfigurationError("INVALID_CERTIFICATE_TRANSITION")); } if ( !z.iso.datetime().safeParse(recordedAt).success || recordedAt < (this.history.at(-1)?.recordedAt ?? "") ) { return Result.fail(new CertificateConfigurationError("INVALID_REQUEST")); } return Result.ok( new CertificateConfiguration( { ...this.props, values, history: [ ...this.history, CertificateConfigurationRevision.create({ values, actorId, recordedAt }), ], }, this.id ) ); } }