using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 租户聚合的 EF Core 仓储实现。
/// </summary>
public sealed class EfTenantRepository(TakeoutAppDbContext context) : ITenantRepository
{
    /// <inheritdoc />
    public Task<Tenant?> FindByIdAsync(long tenantId, CancellationToken cancellationToken = default)
    {
        return context.Tenants
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.Id == tenantId, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<Tenant>> SearchAsync(
        TenantStatus? status,
        string? keyword,
        CancellationToken cancellationToken = default)
    {
        // 1. 构建基础查询
        var query = context.Tenants.AsNoTracking();

        // 2. 按状态过滤
        if (status.HasValue)
        {
            query = query.Where(x => x.Status == status.Value);
        }

        // 3. 按关键字过滤
        if (!string.IsNullOrWhiteSpace(keyword))
        {
            keyword = keyword.Trim();
            query = query.Where(x =>
                EF.Functions.ILike(x.Name, $"%{keyword}%") ||
                EF.Functions.ILike(x.Code, $"%{keyword}%") ||
                EF.Functions.ILike(x.ContactName ?? string.Empty, $"%{keyword}%"));
        }

        // 4. 排序返回
        return await query
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddTenantAsync(Tenant tenant, CancellationToken cancellationToken = default)
    {
        return context.Tenants.AddAsync(tenant, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task UpdateTenantAsync(Tenant tenant, CancellationToken cancellationToken = default)
    {
        context.Tenants.Update(tenant);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task<bool> ExistsByCodeAsync(string code, CancellationToken cancellationToken = default)
    {
        var normalized = code.Trim();
        return context.Tenants.AnyAsync(x => x.Code == normalized, cancellationToken);
    }

    /// <inheritdoc />
    public Task<bool> ExistsByContactPhoneAsync(string phone, CancellationToken cancellationToken = default)
    {
        var normalized = phone.Trim();
        return context.Tenants.AnyAsync(x => x.ContactPhone == normalized, cancellationToken);
    }

    /// <inheritdoc />
    public Task<TenantVerificationProfile?> GetVerificationProfileAsync(long tenantId, CancellationToken cancellationToken = default)
    {
        return context.TenantVerificationProfiles
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.TenantId == tenantId, cancellationToken);
    }

    /// <inheritdoc />
    public async Task UpsertVerificationProfileAsync(TenantVerificationProfile profile, CancellationToken cancellationToken = default)
    {
        // 1. 查询现有实名资料
        var existing = await context.TenantVerificationProfiles
            .FirstOrDefaultAsync(x => x.TenantId == profile.TenantId, cancellationToken);

        if (existing == null)
        {
            // 2. 不存在则新增
            await context.TenantVerificationProfiles.AddAsync(profile, cancellationToken);
            return;
        }

        // 3. 存在则更新当前值
        profile.Id = existing.Id;
        context.Entry(existing).CurrentValues.SetValues(profile);
    }

    /// <inheritdoc />
    public Task<TenantSubscription?> GetActiveSubscriptionAsync(long tenantId, CancellationToken cancellationToken = default)
    {
        return context.TenantSubscriptions
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId)
            .OrderByDescending(x => x.EffectiveTo)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<TenantSubscription?> FindSubscriptionByIdAsync(long tenantId, long subscriptionId, CancellationToken cancellationToken = default)
    {
        return context.TenantSubscriptions
            .FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Id == subscriptionId, cancellationToken);
    }

    /// <inheritdoc />
    public Task AddSubscriptionAsync(TenantSubscription subscription, CancellationToken cancellationToken = default)
    {
        return context.TenantSubscriptions.AddAsync(subscription, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task UpdateSubscriptionAsync(TenantSubscription subscription, CancellationToken cancellationToken = default)
    {
        context.TenantSubscriptions.Update(subscription);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task AddSubscriptionHistoryAsync(TenantSubscriptionHistory history, CancellationToken cancellationToken = default)
    {
        return context.TenantSubscriptionHistories.AddAsync(history, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<TenantSubscriptionHistory>> GetSubscriptionHistoryAsync(long tenantId, CancellationToken cancellationToken = default)
    {
        return await context.TenantSubscriptionHistories
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId)
            .OrderByDescending(x => x.EffectiveFrom)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddAuditLogAsync(TenantAuditLog log, CancellationToken cancellationToken = default)
    {
        return context.TenantAuditLogs.AddAsync(log, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<TenantAuditLog>> GetAuditLogsAsync(long tenantId, CancellationToken cancellationToken = default)
    {
        return await context.TenantAuditLogs
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId)
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        return context.SaveChangesAsync(cancellationToken);
    }
}
