using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Errors;

namespace ErsatzTV.Core;

public static class VersionedAggregateExtensions
{
    /// <summary>
    ///     Optimistic-concurrency pre-check (issue #253). When the caller supplied one or more expected
    ///     versions (the strong <c>If-Match</c> entity-tags), fail with <see cref="PreconditionFailedError" />
    ///     (→ 412) unless the loaded aggregate's version is one of them (RFC 7232 §3.1: any strong match
    ///     proceeds). An <b>empty</b> set never matches → always 412 (a weak/non-canonical tag was sent).
    ///     An absent expectation is a force-write (Phase 1 back-compat). This returns a standalone
    ///     <see cref="Either{L,R}" /> so the 412 is introduced AFTER the validation pipeline and never
    ///     flattened to 422 by <see cref="LanguageExtensions.Apply{T,TR}" /> (see api-conventions §7a).
    /// </summary>
    public static Either<BaseError, T> CheckVersion<T>(this T aggregate, Option<Seq<int>> expectedVersions)
        where T : IVersionedAggregate =>
        expectedVersions.Match(
            Some: versions => versions.Contains(aggregate.Version)
                ? Right<BaseError, T>(aggregate)
                : Left<BaseError, T>(new PreconditionFailedError(
                    "The resource was modified by another request. Reload and try again.")),
            None: () => Right<BaseError, T>(aggregate));
}
