using System.Data;
using Dapper;
using PlotLine.Data;

namespace PlotLine.Services;

public interface IProjectAccessRepository
{
    Task<bool> UserCanAccessProjectAsync(int projectId, int userId);
    Task<bool> UserCanOwnProjectAsync(int projectId, int userId);
    Task<bool> UserCanAccessEntityAsync(string entityType, int entityId, int userId);
}

public interface IProjectAccessService
{
    Task<bool> CanAccessProjectAsync(int projectId);
    Task<bool> CanOwnProjectAsync(int projectId);
    Task<bool> CanAccessEntityAsync(string entityType, int entityId);
}

public sealed class ProjectAccessRepository(ISqlConnectionFactory connectionFactory) : IProjectAccessRepository
{
    public async Task<bool> UserCanAccessProjectAsync(int projectId, int userId)
    {
        using var connection = connectionFactory.CreateConnection();
        return await connection.QuerySingleAsync<bool>(
            "dbo.ProjectAccess_UserCanAccess",
            new { ProjectID = projectId, UserID = userId },
            commandType: CommandType.StoredProcedure);
    }

    public async Task<bool> UserCanOwnProjectAsync(int projectId, int userId)
    {
        using var connection = connectionFactory.CreateConnection();
        return await connection.QuerySingleAsync<bool>(
            "dbo.ProjectAccess_UserCanOwn",
            new { ProjectID = projectId, UserID = userId },
            commandType: CommandType.StoredProcedure);
    }

    public async Task<bool> UserCanAccessEntityAsync(string entityType, int entityId, int userId)
    {
        using var connection = connectionFactory.CreateConnection();
        return await connection.QuerySingleAsync<bool>(
            "dbo.ProjectAccess_UserCanAccessEntity",
            new { EntityType = entityType, EntityID = entityId, UserID = userId },
            commandType: CommandType.StoredProcedure);
    }
}

public sealed class ProjectAccessService(IProjectAccessRepository access, ICurrentUserService currentUser) : IProjectAccessService
{
    public Task<bool> CanAccessProjectAsync(int projectId)
    {
        var userId = currentUser.UserId;
        return userId.HasValue && projectId > 0
            ? access.UserCanAccessProjectAsync(projectId, userId.Value)
            : Task.FromResult(false);
    }

    public Task<bool> CanOwnProjectAsync(int projectId)
    {
        var userId = currentUser.UserId;
        return userId.HasValue && projectId > 0
            ? access.UserCanOwnProjectAsync(projectId, userId.Value)
            : Task.FromResult(false);
    }

    public Task<bool> CanAccessEntityAsync(string entityType, int entityId)
    {
        var userId = currentUser.UserId;
        return userId.HasValue && entityId > 0 && !string.IsNullOrWhiteSpace(entityType)
            ? access.UserCanAccessEntityAsync(entityType, entityId, userId.Value)
            : Task.FromResult(false);
    }
}
