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

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 租户聚合的 EF Core 仓储实现。
/// </summary>
public sealed class EfTenantRepository(TakeoutAppDbContext context, TakeoutLogsDbContext logsContext) : 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>> FindByIdsAsync(IReadOnlyCollection<long> tenantIds, CancellationToken cancellationToken = default)
    {
        if (tenantIds.Count == 0)
        {
            return Array.Empty<Tenant>();
        }

        return await context.Tenants
            .AsNoTracking()
            .Where(x => tenantIds.Contains(x.Id))
            .ToListAsync(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}%") ||
                EF.Functions.ILike(x.ContactPhone ?? string.Empty, $"%{keyword}%"));
        }

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

    /// <inheritdoc />
    public async Task<(IReadOnlyList<Tenant> Items, int Total)> SearchPagedAsync(
        TenantStatus? status,
        TenantVerificationStatus? verificationStatus,
        string? name,
        string? contactName,
        string? contactPhone,
        string? keyword,
        int page,
        int pageSize,
        CancellationToken cancellationToken = default)
    {
        var query = context.Tenants.AsNoTracking();

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

        // 2. 按实名认证状态过滤（未提交视为 Draft）
        if (verificationStatus.HasValue)
        {
            query = from tenant in query
                    join profile in context.TenantVerificationProfiles.AsNoTracking()
                        on tenant.Id equals profile.TenantId into profiles
                    from profile in profiles.DefaultIfEmpty()
                    where (profile == null ? TenantVerificationStatus.Draft : profile.Status) == verificationStatus.Value
                    select tenant;
        }

        // 3. 按名称/联系人/电话过滤（模糊匹配）
        if (!string.IsNullOrWhiteSpace(name))
        {
            var normalizedName = name.Trim();
            query = query.Where(x => EF.Functions.ILike(x.Name, $"%{normalizedName}%"));
        }

        // 4. 按联系人过滤（模糊匹配）
        if (!string.IsNullOrWhiteSpace(contactName))
        {
            var normalizedContactName = contactName.Trim();
            query = query.Where(x => EF.Functions.ILike(x.ContactName ?? string.Empty, $"%{normalizedContactName}%"));
        }

        // 5. 按联系电话过滤（模糊匹配）
        if (!string.IsNullOrWhiteSpace(contactPhone))
        {
            var normalizedContactPhone = contactPhone.Trim();
            query = query.Where(x => EF.Functions.ILike(x.ContactPhone ?? string.Empty, $"%{normalizedContactPhone}%"));
        }

        // 6. 兼容关键字查询：名称/编码/联系人/电话
        if (!string.IsNullOrWhiteSpace(keyword))
        {
            var normalizedKeyword = keyword.Trim();
            query = query.Where(x =>
                EF.Functions.ILike(x.Name, $"%{normalizedKeyword}%") ||
                EF.Functions.ILike(x.Code, $"%{normalizedKeyword}%") ||
                EF.Functions.ILike(x.ContactName ?? string.Empty, $"%{normalizedKeyword}%") ||
                EF.Functions.ILike(x.ContactPhone ?? string.Empty, $"%{normalizedKeyword}%"));
        }

        // 7. 先统计总数，再按创建时间倒序分页
        var total = await query.CountAsync(cancellationToken);

        // 8. 查询当前页数据
        var items = await query
            .OrderByDescending(x => x.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);

        return (items, total);
    }

    /// <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<long?> FindIdByCodeAsync(string code, CancellationToken cancellationToken = default)
    {
        // 1. 标准化编码
        var normalized = code.Trim();

        // 2. 查询租户 ID（仅查询未删除且状态正常的租户）
        return context.Tenants
            .AsNoTracking()
            .Where(x => x.Code == normalized && x.DeletedAt == null)
            .Select(x => (long?)x.Id)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<bool> ExistsByNameAsync(string name, long? excludeTenantId = null, CancellationToken cancellationToken = default)
    {
        // 1. 标准化名称
        var normalized = name.Trim();

        // 2. 构建查询（名称使用 ILike 做不区分大小写的等值匹配）
        var query = context.Tenants
            .AsNoTracking()
            .Where(x => EF.Functions.ILike(x.Name, normalized));

        // 3. 更新场景排除自身
        if (excludeTenantId.HasValue)
        {
            query = query.Where(x => x.Id != excludeTenantId.Value);
        }

        // 4. 判断是否存在
        return query.AnyAsync(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<long?> FindTenantIdByContactPhoneAsync(string phone, CancellationToken cancellationToken = default)
    {
        // 1. 标准化手机号
        var normalized = phone.Trim();
        // 2. 查询租户 ID
        return context.Tenants.AsNoTracking()
            .Where(x => x.ContactPhone == normalized)
            .Select(x => (long?)x.Id)
            .FirstOrDefaultAsync(cancellationToken);
    }

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

    /// <inheritdoc />
    public async Task<IReadOnlyList<TenantVerificationProfile>> GetVerificationProfilesAsync(
        IReadOnlyCollection<long> tenantIds,
        CancellationToken cancellationToken = default)
    {
        // 1. tenantIds 为空直接返回
        if (tenantIds.Count == 0)
        {
            return Array.Empty<TenantVerificationProfile>();
        }

        // 2. 批量查询实名资料
        return await context.TenantVerificationProfiles
            .AsNoTracking()
            .Where(x => x.DeletedAt == null && tenantIds.Contains(x.TenantId))
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task UpsertVerificationProfileAsync(TenantVerificationProfile profile, CancellationToken cancellationToken = default)
    {
        // 1. 查询现有实名资料
        var existing = await context.TenantVerificationProfiles
            .FirstOrDefaultAsync(x => x.DeletedAt == null && 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.DeletedAt == null && x.TenantId == tenantId)
            .OrderByDescending(x => x.EffectiveTo)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<TenantSubscription>> GetSubscriptionsAsync(
        IReadOnlyCollection<long> tenantIds,
        CancellationToken cancellationToken = default)
    {
        // 1. tenantIds 为空直接返回
        if (tenantIds.Count == 0)
        {
            return Array.Empty<TenantSubscription>();
        }

        // 2. 批量查询订阅数据
        return await context.TenantSubscriptions
            .AsNoTracking()
            .Where(x => x.DeletedAt == null && tenantIds.Contains(x.TenantId))
            .OrderByDescending(x => x.EffectiveTo)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<TenantSubscription?> FindSubscriptionByIdAsync(long tenantId, long subscriptionId, CancellationToken cancellationToken = default)
    {
        return context.TenantSubscriptions
            .FirstOrDefaultAsync(
                x => x.DeletedAt == null && 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.DeletedAt == null && x.TenantId == tenantId)
            .OrderByDescending(x => x.EffectiveFrom)
            .ToListAsync(cancellationToken);
    }

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

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

    /// <inheritdoc />
    public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        // 1. 保存业务库变更
        await context.SaveChangesAsync(cancellationToken);

        // 2. 保存日志库变更
        await logsContext.SaveChangesAsync(cancellationToken);
    }
}
