using ManagerService.Controllers;
using ManagerService.Data;
using ManagerService.Data.SubSection;
using ManagerService.DTOs;
using ManagerService.Tests.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace ManagerService.Tests.Controllers
{
///
/// Couvre la persistance des règles de progression d'un parcours — les 3 booléens
/// derrière la question « Comment le visiteur progresse-t-il ? » de manager-app
/// (Libre / Dans l'ordre / Étape par étape) — et le nettoyage des champs morts.
///
public class SectionParcoursControllerTests
{
private SectionParcoursController BuildController(MyInfoMateDbContext db)
{
var controller = new SectionParcoursController(
FakeConfiguration.Create(),
NullLogger.Instance,
db);
FakeUser.SetUser(controller, FakeUser.Create(Permissions.SuperAdmin));
return controller;
}
private static SectionParcours SeedSection(MyInfoMateDbContext db, string id = "sp1", bool showMap = true)
{
var section = new SectionParcours
{
Id = id,
InstanceId = "inst-test",
ConfigurationId = "cfg1",
Label = "Parcours de test",
Title = new List(),
Description = new List(),
ShowMap = showMap,
};
db.Sections.Add(section);
db.SaveChanges();
return section;
}
private static GuidedPathDTO MakePath(string title = "Parcours") => new GuidedPathDTO
{
instanceId = "inst-test",
title = new List { new TranslationDTO { language = "FR", value = title } },
description = new List(),
steps = new List(),
order = 0,
};
// ── Modes de progression ─────────────────────────────────────────────
[Theory]
// Libre : le visiteur choisit ses étapes dans l'ordre qu'il veut
[InlineData(false, false, false)]
// Dans l'ordre : séquence imposée, sans obligation de réussite
[InlineData(true, false, false)]
// Étape par étape : séquence + validation, étapes futures masquées
[InlineData(true, true, true)]
public void CreateGuidedPath_PersistsProgressionFlags(bool isLinear, bool requireSuccess, bool hideNext)
{
using var db = DbContextFactory.Create();
SeedSection(db);
var dto = MakePath();
dto.isLinear = isLinear;
dto.requireSuccessToAdvance = requireSuccess;
dto.hideNextStepsUntilComplete = hideNext;
var result = BuildController(db).CreateGuidedPath("sp1", dto);
Assert.Equal(200, result.StatusCode);
var saved = db.GuidedPaths.Single();
Assert.Equal(isLinear, saved.IsLinear);
Assert.Equal(requireSuccess, saved.RequireSuccessToAdvance);
Assert.Equal(hideNext, saved.HideNextStepsUntilComplete);
}
[Fact]
public void UpdateGuidedPath_SwitchingToFreeNavigation_ClearsSequencingFlags()
{
using var db = DbContextFactory.Create();
SeedSection(db);
var created = BuildController(db).CreateGuidedPath("sp1", MakePath());
var path = Assert.IsType(created.Value);
// Passage « Étape par étape » → « Libre » (ce que fait applyProgressionMode côté manager-app)
path.isLinear = false;
path.requireSuccessToAdvance = false;
path.hideNextStepsUntilComplete = false;
var result = BuildController(db).UpdateGuidedPath(path);
Assert.Equal(200, result.StatusCode);
var saved = db.GuidedPaths.Single();
Assert.False(saved.IsLinear);
Assert.False(saved.RequireSuccessToAdvance);
Assert.False(saved.HideNextStepsUntilComplete);
}
[Fact]
public void CreateGuidedPath_KeepsGameModeMessages()
{
using var db = DbContextFactory.Create();
SeedSection(db);
var dto = MakePath();
dto.isGameMode = true;
dto.gameMessageDebut = new List
{
new TranslationAndResourceDTO { language = "FR", value = "Bienvenue dans l'escape" }
};
dto.gameMessageFin = new List
{
new TranslationAndResourceDTO { language = "FR", value = "Bravo !" }
};
BuildController(db).CreateGuidedPath("sp1", dto);
var saved = db.GuidedPaths.Single();
Assert.True(saved.IsGameMode);
Assert.Equal("Bienvenue dans l'escape", saved.GameMessageDebut.Single().value);
Assert.Equal("Bravo !", saved.GameMessageFin.Single().value);
}
[Fact]
public void CreateGuidedPath_UnknownSection_Returns404()
{
using var db = DbContextFactory.Create();
var result = BuildController(db).CreateGuidedPath("does-not-exist", MakePath());
Assert.Equal(404, result.StatusCode);
}
// ── Étapes ───────────────────────────────────────────────────────────
[Fact]
public void CreateGuidedStep_PersistsGeoTriggerAndTimer()
{
using var db = DbContextFactory.Create();
SeedSection(db);
var created = BuildController(db).CreateGuidedPath("sp1", MakePath());
var pathId = Assert.IsType(created.Value).id;
var step = new GuidedStepDTO
{
title = new List(),
description = new List(),
isGeoTriggered = true,
zoneRadiusMeters = 30,
isStepTimer = true,
timerSeconds = 120,
order = 0,
};
var result = BuildController(db).CreateGuidedStep(pathId, step);
Assert.Equal(200, result.StatusCode);
var saved = db.GuidedSteps.Single();
Assert.True(saved.IsGeoTriggered);
Assert.Equal(30, saved.ZoneRadiusMeters);
Assert.True(saved.IsStepTimer);
Assert.Equal(120, saved.TimerSeconds);
}
[Fact]
public void GetAllGuidedPathFromSection_ReturnsPathsOrderedByOrder()
{
using var db = DbContextFactory.Create();
SeedSection(db);
var controller = BuildController(db);
var second = MakePath("Second"); second.order = 1;
var first = MakePath("Premier"); first.order = 0;
controller.CreateGuidedPath("sp1", second);
controller.CreateGuidedPath("sp1", first);
var result = BuildController(db).GetAllGuidedPathFromSection("sp1");
Assert.Equal(200, result.StatusCode);
var paths = Assert.IsAssignableFrom>(result.Value).ToList();
Assert.Equal(2, paths.Count);
Assert.Equal(new int?[] { 0, 1 }, paths.Select(p => p.order).ToArray());
}
}
}