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 { FolderMappingRevision } from "./folder-mapping-revision.entity"; import { FOLDER_STATE_TRANSITIONS, FolderMappingError } from "./folder-mapping-values"; import type { FolderMappingValues } from "./value-objects/folder-mapping-values.vo"; type Props = Readonly<{ companyId: UniqueID; values: FolderMappingValues; history: readonly FolderMappingRevision[]; }>; export class FolderMapping extends AggregateRoot { private constructor(props: Props, id?: UniqueID) { super(Object.freeze({ ...props, history: Object.freeze([...props.history]) }), id); } static create( companyId: UniqueID, values: FolderMappingValues, actorId: UniqueID, recordedAt: string ): Result { if ( !( z.iso.datetime().safeParse(recordedAt).success && ["pending", "configured"].includes(values.state) ) ) { return Result.fail(new FolderMappingError("INVALID_FOLDER_TRANSITION")); } return Result.ok( new FolderMapping({ companyId, values, history: [FolderMappingRevision.create({ values, actorId, recordedAt })], }) ); } static rehydrate(props: Props, id: UniqueID) { return new FolderMapping(props, id); } get companyId() { return this.props.companyId; } get values() { return this.props.values; } get history() { return this.props.history; } update( values: FolderMappingValues, actorId: UniqueID, recordedAt: string ): Result { if (this.values.equals(values)) { return Result.ok(this); } if (!this.values.sameTarget(values)) { return Result.fail(new FolderMappingError("FOLDER_TARGET_IMMUTABLE")); } if ( !FOLDER_STATE_TRANSITIONS[this.values.state].some((state) => state === values.state) || (this.values.closed && !this.values.equals(values)) ) { return Result.fail(new FolderMappingError("INVALID_FOLDER_TRANSITION")); } if ( !z.iso.datetime().safeParse(recordedAt).success || recordedAt < (this.history.at(-1)?.recordedAt ?? "") ) { return Result.fail(new FolderMappingError("INVALID_REQUEST")); } return Result.ok( new FolderMapping( { ...this.props, values, history: [...this.history, FolderMappingRevision.create({ values, actorId, recordedAt })], }, this.id ) ); } }