using ColaFlow.Modules.Identity.Domain.Aggregates.Users;
using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
using ColaFlow.Modules.Identity.Domain.Repositories;
using Microsoft.EntityFrameworkCore;

namespace ColaFlow.Modules.Identity.Infrastructure.Persistence.Repositories;

public class UserTenantRoleRepository(IdentityDbContext context) : IUserTenantRoleRepository
{
    public async Task<UserTenantRole?> GetByUserAndTenantAsync(
        Guid userId,
        Guid tenantId,
        CancellationToken cancellationToken = default)
    {
        // Create value objects to avoid LINQ translation issues with .Value property
        var userIdVO = UserId.Create(userId);
        var tenantIdVO = TenantId.Create(tenantId);

        return await context.UserTenantRoles
            .FirstOrDefaultAsync(
                utr => utr.UserId == userIdVO && utr.TenantId == tenantIdVO,
                cancellationToken);
    }

    public async Task<IReadOnlyList<UserTenantRole>> GetByUserAsync(
        Guid userId,
        CancellationToken cancellationToken = default)
    {
        // Create value object to avoid LINQ translation issues with .Value property
        var userIdVO = UserId.Create(userId);

        return await context.UserTenantRoles
            .Where(utr => utr.UserId == userIdVO)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<UserTenantRole>> GetByTenantAsync(
        Guid tenantId,
        CancellationToken cancellationToken = default)
    {
        // Create value object to avoid LINQ translation issues with .Value property
        var tenantIdVO = TenantId.Create(tenantId);

        return await context.UserTenantRoles
            .Where(utr => utr.TenantId == tenantIdVO)
            // Note: User navigation is ignored in EF config, so Include is skipped
            .ToListAsync(cancellationToken);
    }

    public async Task AddAsync(UserTenantRole role, CancellationToken cancellationToken = default)
    {
        await context.UserTenantRoles.AddAsync(role, cancellationToken);
        await context.SaveChangesAsync(cancellationToken);
    }

    public async Task UpdateAsync(UserTenantRole role, CancellationToken cancellationToken = default)
    {
        context.UserTenantRoles.Update(role);
        await context.SaveChangesAsync(cancellationToken);
    }

    public async Task DeleteAsync(UserTenantRole role, CancellationToken cancellationToken = default)
    {
        context.UserTenantRoles.Remove(role);
        await context.SaveChangesAsync(cancellationToken);
    }

    public async Task<(List<UserTenantRole> Items, int TotalCount)> GetTenantUsersWithRolesAsync(
        Guid tenantId,
        int pageNumber = 1,
        int pageSize = 20,
        string? searchTerm = null,
        CancellationToken cancellationToken = default)
    {
        var tenantIdVO = TenantId.Create(tenantId);

        var query = context.UserTenantRoles
            .Where(utr => utr.TenantId == tenantIdVO);

        // Note: Search filtering would require joining with Users table
        // Since User navigation is ignored in EF config, search is handled at application layer

        var totalCount = await query.CountAsync(cancellationToken);

        var items = await query
            .OrderBy(utr => utr.AssignedAt)
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);

        return (items, totalCount);
    }

    public async Task<bool> IsLastTenantOwnerAsync(
        Guid tenantId,
        Guid userId,
        CancellationToken cancellationToken = default)
    {
        var tenantIdVO = TenantId.Create(tenantId);

        var ownerCount = await context.UserTenantRoles
            .Where(utr => utr.TenantId == tenantIdVO && utr.Role == TenantRole.TenantOwner)
            .CountAsync(cancellationToken);

        if (ownerCount <= 1)
        {
            var userIdVO = UserId.Create(userId);
            var userIsOwner = await context.UserTenantRoles
                .AnyAsync(utr => utr.TenantId == tenantIdVO &&
                                utr.UserId == userIdVO &&
                                utr.Role == TenantRole.TenantOwner,
                          cancellationToken);

            return userIsOwner;
        }

        return false;
    }

    public async Task<int> CountByTenantAndRoleAsync(
        Guid tenantId,
        TenantRole role,
        CancellationToken cancellationToken = default)
    {
        var tenantIdVO = TenantId.Create(tenantId);

        return await context.UserTenantRoles
            .CountAsync(utr => utr.TenantId == tenantIdVO && utr.Role == role,
                       cancellationToken);
    }
}
