using System.Security.Claims;
using GmRelay.Shared.Domain;

namespace GmRelay.Web.Services;

public sealed class AuthorizedMembershipService(ISessionStore sessionStore, IHttpContextAccessor httpContextAccessor)
{
    private (string Platform, string ExternalUserId, string Name)? GetCurrentIdentity()
    {
        var user = httpContextAccessor.HttpContext?.User;
        if (user is null || !user.TryGetPlatformIdentity(out var platform, out var externalUserId))
            return null;

        var name = user.FindFirst(ClaimTypes.Name)?.Value ?? externalUserId;
        return (platform, externalUserId, name);
    }

    public async Task<Guid> ApplyForCurrentUserAsync(Guid groupId, string? message)
    {
        var identity = GetCurrentIdentity();
        if (identity is null)
            throw new InvalidOperationException("User is not authenticated.");

        var playerId = await sessionStore.GetPlayerIdByPlatformIdentityAsync(identity.Value.Platform, identity.Value.ExternalUserId);
        if (playerId is null)
        {
            throw new InvalidOperationException("Player record not found for current user.");
        }

        var normalizedMessage = string.IsNullOrWhiteSpace(message) ? null : message.Trim();
        if (normalizedMessage?.Length > 1000)
        {
            throw new InvalidOperationException("Сообщение заявки должно быть не длиннее 1000 символов.");
        }

        return await sessionStore.ApplyForMembershipAsync(groupId, playerId.Value, normalizedMessage);
    }

    public async Task<List<WebMembership>> GetMineAsync()
    {
        var identity = GetCurrentIdentity();
        if (identity is null)
            return [];

        var playerId = await sessionStore.GetPlayerIdByPlatformIdentityAsync(identity.Value.Platform, identity.Value.ExternalUserId);
        if (playerId is null)
            return [];

        return await sessionStore.GetMembershipsForPlayerAsync(playerId.Value);
    }

    public async Task LeaveClubForCurrentUserAsync(Guid membershipId)
    {
        var identity = GetCurrentIdentity();
        if (identity is null)
            throw new InvalidOperationException("User is not authenticated.");

        var playerId = await sessionStore.GetPlayerIdByPlatformIdentityAsync(identity.Value.Platform, identity.Value.ExternalUserId);
        if (playerId is null)
            throw new InvalidOperationException("Player record not found for current user.");

        await sessionStore.LeaveClubMembershipAsync(membershipId, playerId.Value);
    }

    public async Task<List<WebPendingApplication>> GetPendingApplicationsAsync(Guid groupId)
    {
        var identity = GetCurrentIdentity();
        if (identity is null)
            throw new InvalidOperationException("User is not authenticated.");

        if (!await sessionStore.IsGroupManagerAsync(groupId, identity.Value.Platform, identity.Value.ExternalUserId))
        {
            throw new SessionAccessDeniedException(groupId, identity.Value.ExternalUserId);
        }

        return await sessionStore.GetPendingApplicationsAsync(groupId);
    }

    public async Task<int> GetPendingApplicationsCountForCurrentGmAsync(Guid groupId)
    {
        var identity = GetCurrentIdentity();
        if (identity is null)
            return 0;

        if (!await sessionStore.IsGroupManagerAsync(groupId, identity.Value.Platform, identity.Value.ExternalUserId))
            return 0;

        return await sessionStore.GetPendingApplicationsCountAsync(groupId);
    }

    public async Task ApproveForCurrentGmAsync(Guid membershipId)
    {
        var (approverPlayerId, groupId) = await ResolveMembershipContextForGmAsync(membershipId);
        await sessionStore.ApproveMembershipAsync(membershipId, approverPlayerId);
    }

    public async Task RejectForCurrentGmAsync(Guid membershipId)
    {
        var (approverPlayerId, groupId) = await ResolveMembershipContextForGmAsync(membershipId);
        await sessionStore.RejectMembershipAsync(membershipId, approverPlayerId);
    }

    private async Task<(Guid ApproverPlayerId, Guid GroupId)> ResolveMembershipContextForGmAsync(Guid membershipId)
    {
        var identity = GetCurrentIdentity();
        if (identity is null)
            throw new InvalidOperationException("User is not authenticated.");

        var playerId = await sessionStore.GetPlayerIdByPlatformIdentityAsync(identity.Value.Platform, identity.Value.ExternalUserId);
        if (playerId is null)
            throw new InvalidOperationException("Player record not found for current user.");

        var groupId = await sessionStore.GetGroupIdForMembershipAsync(membershipId);
        if (groupId is null)
            throw new InvalidOperationException($"Membership {membershipId} not found.");

        if (!await sessionStore.IsGroupManagerAsync(groupId.Value, identity.Value.Platform, identity.Value.ExternalUserId))
        {
            throw new SessionAccessDeniedException(groupId.Value, identity.Value.ExternalUserId);
        }

        return (playerId.Value, groupId.Value);
    }
}
