using RpgRoller.Domain;

namespace RpgRoller.Services;

public static class GameContextResolver
{
    public static UserAccount? ResolveUserLocked(GameStateStore stateStore, string sessionToken)
    {
        if (string.IsNullOrWhiteSpace(sessionToken))
            return null;

        if (!stateStore.SessionsByToken.TryGetValue(sessionToken, out var session))
            return null;

        return stateStore.UsersById.GetValueOrDefault(session.UserId);
    }

    public static ServiceResult<(UserAccount User, Campaign Campaign)> ResolveCampaignContextLocked(GameStateStore stateStore, string sessionToken, Guid campaignId)
    {
        var user = ResolveUserLocked(stateStore, sessionToken);
        if (user is null)
            return ServiceResult<(UserAccount User, Campaign Campaign)>.Failure("unauthorized", "You must be logged in.");

        if (!stateStore.CampaignsById.TryGetValue(campaignId, out var campaign))
            return ServiceResult<(UserAccount User, Campaign Campaign)>.Failure("campaign_not_found", "Campaign was not found.");

        if (!GameAuthorization.CanViewCampaign(stateStore, user.Id, campaign.Id))
            return ServiceResult<(UserAccount User, Campaign Campaign)>.Failure("forbidden", "You are not a participant in this campaign.");

        return ServiceResult<(UserAccount User, Campaign Campaign)>.Success((user, campaign));
    }

    public static bool TryResolveCharacterCampaignLocked(GameStateStore stateStore, Character character, out Campaign campaign, out ServiceError? error)
    {
        campaign = null!;
        if (!character.CampaignId.HasValue || !stateStore.CampaignsById.TryGetValue(character.CampaignId.Value, out var resolvedCampaign))
        {
            error = new("character_not_in_campaign", "Character is not linked to a campaign.");
            return false;
        }

        campaign = resolvedCampaign;
        error = null;
        return true;
    }
}