using GerbilManagerWebAPI.Models;

namespace GerbilManagerWebAPI.Services
{
    /// <summary>
    /// Central status-derivation logic. Every write path (create/update gerbil, SaleContract
    /// Abgabe, import, startup sweep) calls Apply() after setting the other fields so the
    /// derived statuses (Deceased, GivenAway) are always consistent.
    ///
    /// Precedence (highest wins):
    ///   1) DateOfDeath set           → Deceased (explicit, always)
    ///   2) Abgabe (ReceiverContactId set) → GivenAway
    ///   3) Age > MaxAgeYears without a death date or Abgabe → Deceased (presumed)
    ///   4) User-supplied {Breeding, Pet, ForSale}; defaults Breeding if invalid
    ///
    /// Age-based death is time-dependent. The stored column is kept up-to-date by:
    ///   a) Apply() on every write (catches the animal at write time)
    ///   b) A startup sweep in Program.cs (catches animals that silently crossed the threshold)
    /// Gridify filters on the stored value, so status==Breeding never surfaces >7y animals.
    /// </summary>
    public static class GerbilStatusService
    {
        public const int MaxAgeYears = 6;

        /// <summary>Derives and sets g.Status using the gerbil's current field values.
        /// Must be called AFTER all other fields (DateOfDeath, ReceiverContactId, DateOfBirth)
        /// have been applied. today = DateOnly.FromDateTime(DateTime.UtcNow).</summary>
        public static void Apply(Gerbil g, DateOnly today)
        {
            g.Status = Derive(g.Status, g.DateOfBirth, g.DateOfDeath,
                isAbgegeben: g.ReceiverContactId is not null, today);
        }

        /// <summary>Pure derivation — useful for tests and the migration backfill.</summary>
        public static GerbilStatus Derive(
            GerbilStatus requested,
            DateOnly? dateOfBirth,
            DateOnly? dateOfDeath,
            bool isAbgegeben,
            DateOnly today)
        {
            if (dateOfDeath is not null) return GerbilStatus.Deceased;
            if (isAbgegeben) return GerbilStatus.GivenAway;
            if (dateOfBirth is not null && IsOlderThan(dateOfBirth.Value, MaxAgeYears, today))
                return GerbilStatus.Deceased;
            return requested is GerbilStatus.Breeding or GerbilStatus.Pet or GerbilStatus.ForSale
                ? requested : GerbilStatus.Breeding;
        }

        private static bool IsOlderThan(DateOnly dob, int years, DateOnly today) =>
            today >= dob.AddYears(years);
    }
}
