using Theriapolis.Core;
using Theriapolis.Core.Persistence;
using Theriapolis.Core.Persistence.SaveMigrations;
using Xunit;

namespace Theriapolis.Tests.Persistence;

/// <summary>
/// Phase 6 M2 — additive V5→V6 migration. Unlike V4→V5 (rejection), v5
/// saves are accepted and migrated up by zero-filling the new typed
/// reputation containers.
/// </summary>
public sealed class V5ToV6MigrationTests
{
    [Fact]
    public void V5Header_IsAcceptedByMigration()
    {
        var header = new SaveHeader { Version = 5 };
        Assert.True(SaveCodec.IsCompatible(header),
            "v5 must remain readable post-Phase-6 (MIN_VERSION = 5).");

        var body = new SaveBody();
        bool ok = Migrations.MigrateUp(header, body);
        Assert.True(ok);
        Assert.Equal(C.SAVE_SCHEMA_VERSION, header.Version);
    }

    [Fact]
    public void V6_NewBody_HasEmptyReputationState()
    {
        var body = new SaveBody();
        Assert.NotNull(body.ReputationState);
        Assert.Empty(body.ReputationState.FactionStandings);
        Assert.Empty(body.ReputationState.Personal);
        Assert.Empty(body.ReputationState.Ledger);
    }

    [Fact]
    public void V5SaveBody_AfterMigration_HasEmptyReputation()
    {
        // Construct what a Phase-5-saved body might look like — v5 fields
        // (Player, Clock, ModifiedChunks, ModifiedWorldTiles, Flags,
        // PlayerCharacter, NpcRoster, ActiveEncounter), no v6 fields.
        var header = new SaveHeader { Version = 5 };
        var body = new SaveBody
        {
            Player = new() { Name = "Old Hand", PositionX = 50, PositionY = 50 },
        };
        body.Flags["debug-flag"] = 1;

        bool ok = Migrations.MigrateUp(header, body);
        Assert.True(ok);
        // Migration chains all the way up to the current schema version.
        Assert.Equal(C.SAVE_SCHEMA_VERSION, header.Version);

        // V5 fields must survive untouched.
        Assert.Equal("Old Hand", body.Player.Name);
        Assert.Equal(1, body.Flags["debug-flag"]);

        // V6 fields must be empty (the migration does not synthesise data).
        Assert.NotNull(body.ReputationState);
        Assert.Empty(body.ReputationState.FactionStandings);
        Assert.Empty(body.ReputationState.Personal);
    }

    [Fact]
    public void NewSaveHeader_DefaultsToCurrentSchemaVersion()
    {
        // Schema version increments per phase (Phase 6 = v6, Phase 6.5 = v7);
        // SaveHeader picks up the constant.
        var header = new SaveHeader();
        Assert.Equal(C.SAVE_SCHEMA_VERSION, header.Version);
    }
}
