namespace Fengling.Platform.Infrastructure;

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;

public class TenantStore<TContext> : ITenantStore
where TContext : PlatformDbContext
{
    private readonly TContext _context;
    private readonly DbSet<Tenant> _tenants;

    public TenantStore(TContext context)
    {
        _context = context;
        _tenants = context.Tenants;
    }

    public void Dispose() { }

    public virtual Task<Tenant?> FindByIdAsync(long? tenantId, CancellationToken cancellationToken = default)
    {
        if (tenantId == null) return Task.FromResult<Tenant?>(null);
        return _tenants.FirstOrDefaultAsync(t => t.Id == tenantId, cancellationToken);
    }

    public virtual Task<Tenant?> FindByTenantCodeAsync(string tenantCode, CancellationToken cancellationToken = default)
    {
        return _tenants.FirstOrDefaultAsync(t => t.TenantCode == tenantCode, cancellationToken);
    }

    public virtual async Task<IList<Tenant>> GetAllAsync(CancellationToken cancellationToken = default)
    {
        return await _tenants.ToListAsync(cancellationToken);
    }

    public virtual async Task<IList<Tenant>> GetPagedAsync(int page, int pageSize, string? name = null,
        string? tenantCode = null, TenantStatus? status = null, CancellationToken cancellationToken = default)
    {
        var query = _tenants.AsQueryable();

        if (!string.IsNullOrEmpty(name))
            query = query.Where(t => t.Name.Contains(name));

        if (!string.IsNullOrEmpty(tenantCode))
            query = query.Where(t => t.TenantCode.Contains(tenantCode));

        if (status.HasValue)
            query = query.Where(t => t.Status == status);

        return await query
            .OrderByDescending(t => t.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);
    }

    public virtual async Task<int> GetCountAsync(string? name = null, string? tenantCode = null,
        TenantStatus? status = null, CancellationToken cancellationToken = default)
    {
        var query = _tenants.AsQueryable();

        if (!string.IsNullOrEmpty(name))
            query = query.Where(t => t.Name.Contains(name));

        if (!string.IsNullOrEmpty(tenantCode))
            query = query.Where(t => t.TenantCode.Contains(tenantCode));

        if (status.HasValue)
            query = query.Where(t => t.Status == status);

        return await query.CountAsync(cancellationToken);
    }

    public virtual async Task<IdentityResult> CreateAsync(Tenant tenant, CancellationToken cancellationToken = default)
    {
        _tenants.Add(tenant);
        await _context.SaveChangesAsync(cancellationToken);
        return IdentityResult.Success;
    }

    public virtual async Task<IdentityResult> UpdateAsync(Tenant tenant, CancellationToken cancellationToken = default)
    {
        tenant.UpdatedAt = DateTime.UtcNow;
        _tenants.Update(tenant);
        await _context.SaveChangesAsync(cancellationToken);
        return IdentityResult.Success;
    }

    public virtual async Task<IdentityResult> DeleteAsync(Tenant tenant, CancellationToken cancellationToken = default)
    {
        _tenants.Remove(tenant);
        await _context.SaveChangesAsync(cancellationToken);
        return IdentityResult.Success;
    }

    public virtual async Task<int> GetUserCountAsync(long tenantId, CancellationToken cancellationToken = default)
    {
        return await _context.Users.CountAsync(u => u.TenantInfo.TenantId == tenantId && !u.IsDeleted, cancellationToken);
    }

    public virtual Task<string> GetTenantCodeAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.TenantCode);

    public virtual Task<string> GetNameAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.Name);

    public virtual Task<string> GetContactNameAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.ContactName);

    public virtual Task<string> GetContactEmailAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.ContactEmail);

    public virtual Task<string?> GetContactPhoneAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.ContactPhone);

    public virtual Task<int?> GetMaxUsersAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.MaxUsers);

    public virtual Task<string?> GetDescriptionAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.Description);

    public virtual Task<TenantStatus> GetStatusAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.Status);

    public virtual Task<DateTime?> GetExpiresAtAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.ExpiresAt);

    public virtual Task<DateTime> GetCreatedAtAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.CreatedAt);

    public virtual Task<DateTime?> GetUpdatedAtAsync(Tenant tenant, CancellationToken cancellationToken = default)
        => Task.FromResult(tenant.UpdatedAt);

    public virtual Task SetTenantCodeAsync(Tenant tenant, string code, CancellationToken cancellationToken = default)
    {
        tenant.TenantCode = code;
        return Task.CompletedTask;
    }

    public virtual Task SetNameAsync(Tenant tenant, string name, CancellationToken cancellationToken = default)
    {
        tenant.Name = name;
        return Task.CompletedTask;
    }

    public virtual Task SetContactNameAsync(Tenant tenant, string name, CancellationToken cancellationToken = default)
    {
        tenant.ContactName = name;
        return Task.CompletedTask;
    }

    public virtual Task SetContactEmailAsync(Tenant tenant, string email, CancellationToken cancellationToken = default)
    {
        tenant.ContactEmail = email;
        return Task.CompletedTask;
    }

    public virtual Task SetContactPhoneAsync(Tenant tenant, string? phone, CancellationToken cancellationToken = default)
    {
        tenant.ContactPhone = phone;
        return Task.CompletedTask;
    }

    public virtual Task SetMaxUsersAsync(Tenant tenant, int? maxUsers, CancellationToken cancellationToken = default)
    {
        tenant.MaxUsers = maxUsers;
        return Task.CompletedTask;
    }

    public virtual Task SetDescriptionAsync(Tenant tenant, string? description, CancellationToken cancellationToken = default)
    {
        tenant.Description = description;
        return Task.CompletedTask;
    }

    public virtual Task SetStatusAsync(Tenant tenant, TenantStatus status, CancellationToken cancellationToken = default)
    {
        tenant.Status = status;
        return Task.CompletedTask;
    }

    public virtual Task SetExpiresAtAsync(Tenant tenant, DateTime? expiresAt, CancellationToken cancellationToken = default)
    {
        tenant.ExpiresAt = expiresAt;
        return Task.CompletedTask;
    }
}
