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

namespace Fengling.Platform.Infrastructure;

/// <summary>
/// 服务实例存储实现
/// </summary>
public class InstanceStore<TContext> : IInstanceStore
    where TContext : PlatformDbContext
{
    private readonly TContext _context;
    private readonly DbSet<GwServiceInstance> _instances;

    public InstanceStore(TContext context)
    {
        _context = context;
        _instances = context.GwServiceInstances;
    }

    public void Dispose() { }

    public virtual Task<GwServiceInstance?> FindByIdAsync(long? id, CancellationToken cancellationToken = default)
    {
        if (id == null) return Task.FromResult<GwServiceInstance?>(null);
        return _instances.FirstOrDefaultAsync(i => i.Id == id, cancellationToken);
    }

    public virtual Task<GwServiceInstance?> FindByClusterIdAsync(string clusterId, CancellationToken cancellationToken = default)
    {
        return _instances.FirstOrDefaultAsync(i => i.ClusterId == clusterId && !i.IsDeleted, cancellationToken);
    }

    public virtual Task<GwServiceInstance?> FindByDestinationAsync(string clusterId, string destinationId, CancellationToken cancellationToken = default)
    {
        return _instances.FirstOrDefaultAsync(i => i.ClusterId == clusterId && i.DestinationId == destinationId && !i.IsDeleted, cancellationToken);
    }

    public virtual async Task<IList<GwServiceInstance>> GetAllAsync(CancellationToken cancellationToken = default)
    {
        return await _instances.Where(i => !i.IsDeleted).ToListAsync(cancellationToken);
    }

    public virtual async Task<IList<GwServiceInstance>> GetPagedAsync(int page, int pageSize, string? clusterId = null,
        InstanceHealth? health = null, InstanceStatus? status = null, CancellationToken cancellationToken = default)
    {
        var query = _instances.AsQueryable();

        if (!string.IsNullOrEmpty(clusterId))
            query = query.Where(i => i.ClusterId.Contains(clusterId));

        if (health.HasValue)
            query = query.Where(i => i.Health == (int)health.Value);

        if (status.HasValue)
            query = query.Where(i => i.Status == (int)status.Value);

        return await query
            .Where(i => !i.IsDeleted)
            .OrderByDescending(i => i.CreatedTime)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);
    }

    public virtual async Task<int> GetCountAsync(string? clusterId = null,
        InstanceHealth? health = null, InstanceStatus? status = null, CancellationToken cancellationToken = default)
    {
        var query = _instances.AsQueryable();

        if (!string.IsNullOrEmpty(clusterId))
            query = query.Where(i => i.ClusterId.Contains(clusterId));

        if (health.HasValue)
            query = query.Where(i => i.Health == (int)health.Value);

        if (status.HasValue)
            query = query.Where(i => i.Status == (int)status.Value);

        return await query.Where(i => !i.IsDeleted).CountAsync(cancellationToken);
    }

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

    public virtual async Task<IdentityResult> UpdateAsync(GwServiceInstance instance, CancellationToken cancellationToken = default)
    {
        instance.UpdatedTime = DateTime.UtcNow;
        _instances.Update(instance);
        await _context.SaveChangesAsync(cancellationToken);
        return IdentityResult.Success;
    }

    public virtual async Task<IdentityResult> DeleteAsync(GwServiceInstance instance, CancellationToken cancellationToken = default)
    {
        // 软删除
        instance.IsDeleted = true;
        instance.UpdatedTime = DateTime.UtcNow;
        _instances.Update(instance);
        await _context.SaveChangesAsync(cancellationToken);
        return IdentityResult.Success;
    }
}
