using RpgRoller.Domain;

namespace RpgRoller.Services;

public sealed class GameStateStore
{
    public GameCampaignStateTracker GetOrCreateCampaignStateLocked(Guid campaignId)
    {
        if (!CampaignStateById.TryGetValue(campaignId, out var state))
        {
            state = new();
            CampaignStateById[campaignId] = state;
        }

        return state;
    }

    public void RebuildCampaignStateLocked()
    {
        CampaignStateById.Clear();

        foreach (var campaignId in CampaignsById.Keys)
            CampaignStateById[campaignId] = new();

        foreach (var character in CharactersById.Values.Where(character => character.CampaignId.HasValue))
            AddCharacterStateLocked(character.CampaignId, character.Id);
    }

    public void AddCharacterStateLocked(Guid? campaignId, Guid characterId)
    {
        if (!campaignId.HasValue || !CampaignsById.ContainsKey(campaignId.Value))
            return;

        var state = GetOrCreateCampaignStateLocked(campaignId.Value);
        state.CharacterVersions[characterId] = 1;
    }

    public void RemoveCharacterStateLocked(Guid? campaignId, Guid characterId)
    {
        if (!campaignId.HasValue || !CampaignStateById.TryGetValue(campaignId.Value, out var state))
            return;

        state.CharacterVersions.Remove(characterId);
    }

    public void TouchRosterLocked(Guid? campaignId)
    {
        if (!campaignId.HasValue || !CampaignsById.ContainsKey(campaignId.Value))
            return;

        var state = GetOrCreateCampaignStateLocked(campaignId.Value);
        state.TotalVersion += 1;
        state.RosterVersion += 1;
    }

    public void TouchCharacterLocked(Guid? campaignId, Guid characterId)
    {
        if (!campaignId.HasValue || !CampaignsById.ContainsKey(campaignId.Value))
            return;

        var state = GetOrCreateCampaignStateLocked(campaignId.Value);
        state.TotalVersion += 1;
        state.CharacterVersions[characterId] = state.CharacterVersions.GetValueOrDefault(characterId, 1) + 1;
    }

    public void TouchLogLocked(Guid? campaignId)
    {
        if (!campaignId.HasValue || !CampaignsById.ContainsKey(campaignId.Value))
            return;

        var state = GetOrCreateCampaignStateLocked(campaignId.Value);
        state.TotalVersion += 1;
        state.LogVersion += 1;
    }

    public object Gate { get; } = new();
    public Dictionary<Guid, Campaign> CampaignsById { get; } = [];
    public Dictionary<Guid, GameCampaignStateTracker> CampaignStateById { get; } = [];
    public Dictionary<Guid, Character> CharactersById { get; } = [];
    public List<RollLogEntry> RollLog { get; } = [];
    public Dictionary<string, UserSession> SessionsByToken { get; } = new(StringComparer.Ordinal);
    public Dictionary<Guid, SkillGroup> SkillGroupsById { get; } = [];
    public Dictionary<Guid, Skill> SkillsById { get; } = [];
    public Dictionary<string, Guid> UserIdsByUsername { get; } = new(StringComparer.Ordinal);
    public Dictionary<Guid, UserAccount> UsersById { get; } = [];
}

public sealed class GameCampaignStateTracker
{
    public long TotalVersion { get; set; } = 1;
    public long RosterVersion { get; set; } = 1;
    public long LogVersion { get; set; } = 1;
    public Dictionary<Guid, long> CharacterVersions { get; } = [];
}