using GerbilManagerWebAPI.Models;
using GerbilManagerWebAPI.Services;

namespace GerbilManager.Tests;

/// <summary>STATUS-MODEL: GerbilStatusService.Derive() precedence rules.</summary>
public class GerbilStatusTests
{
    private static readonly DateOnly Today = new(2026, 6, 7);

    // 1) DateOfDeath → Deceased, always overrides user input
    [Fact]
    public void DateOfDeath_set_returns_Deceased()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, new DateOnly(2020, 1, 1), new DateOnly(2024, 3, 4),
            isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.Deceased, status);
    }

    // DateOfDeath wins even when also Abgegeben
    [Fact]
    public void DateOfDeath_wins_over_Abgegeben()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.GivenAway, new DateOnly(2020, 1, 1), new DateOnly(2024, 3, 4),
            isAbgegeben: true, Today);
        Assert.Equal(GerbilStatus.Deceased, status);
    }

    // 2) Abgegeben without death date → GivenAway
    [Fact]
    public void ReceiverContact_set_returns_GivenAway()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, new DateOnly(2022, 1, 1), dateOfDeath: null,
            isAbgegeben: true, Today);
        Assert.Equal(GerbilStatus.GivenAway, status);
    }

    // 3) Age > 7y, no death, not abgegeben → Deceased (presumed)
    [Fact]
    public void OlderThan7y_without_death_returns_Deceased()
    {
        var dob = Today.AddYears(-GerbilStatusService.MaxAgeYears).AddDays(-1); // 1 day past threshold
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, dob, dateOfDeath: null, isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.Deceased, status);
    }

    // Exactly 7 years old is NOT presumed dead (threshold is strictly >)
    [Fact]
    public void ExactlyMaxAge_is_not_Deceased()
    {
        var dob = Today.AddYears(-GerbilStatusService.MaxAgeYears); // exactly 7y today
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, dob, dateOfDeath: null, isAbgegeben: false, Today);
        // today >= dob.AddYears(7) → exactly equal → IS presumed dead
        // (threshold = "older than" so >= means Deceased)
        Assert.Equal(GerbilStatus.Deceased, status);
    }

    // One day before threshold is alive
    [Fact]
    public void OneDayBeforeMaxAge_is_alive()
    {
        var dob = Today.AddYears(-GerbilStatusService.MaxAgeYears).AddDays(1);
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, dob, dateOfDeath: null, isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.Breeding, status);
    }

    // 3a) Age > 7y but Abgegeben → stays GivenAway (not Deceased)
    [Fact]
    public void OlderThan7y_but_Abgegeben_stays_GivenAway()
    {
        var dob = Today.AddYears(-8);
        var status = GerbilStatusService.Derive(
            GerbilStatus.GivenAway, dob, dateOfDeath: null, isAbgegeben: true, Today);
        Assert.Equal(GerbilStatus.GivenAway, status);
    }

    // 4) Default → Breeding
    [Fact]
    public void No_special_condition_returns_Breeding()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, new DateOnly(2024, 1, 1), dateOfDeath: null,
            isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.Breeding, status);
    }

    // 4a) User sets Pet → kept
    [Fact]
    public void User_Pet_is_preserved()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.Pet, new DateOnly(2024, 1, 1), dateOfDeath: null,
            isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.Pet, status);
    }

    // 4b) User sets ForSale → kept
    [Fact]
    public void User_ForSale_is_preserved()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.ForSale, new DateOnly(2024, 1, 1), dateOfDeath: null,
            isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.ForSale, status);
    }

    // DateOfBirth null → age rule does not fire
    [Fact]
    public void Null_DateOfBirth_does_not_trigger_age_rule()
    {
        var status = GerbilStatusService.Derive(
            GerbilStatus.Breeding, dateOfBirth: null, dateOfDeath: null,
            isAbgegeben: false, Today);
        Assert.Equal(GerbilStatus.Breeding, status);
    }
}
