using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TakeoutSaaS.Domain.Dictionary.Entities;
using TakeoutSaaS.Domain.SystemParameters.Entities;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Infrastructure.App.Options;
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;

namespace TakeoutSaaS.Infrastructure.App.Persistence;

/// <summary>
/// 业务数据种子，确保默认租户与基础字典可重复执行。
/// </summary>
/// <remarks>
/// 初始化种子服务。
/// </remarks>
public sealed class AppDataSeeder(
    IServiceProvider serviceProvider,
    ILogger<AppDataSeeder> logger,
    IOptions<AppSeedOptions> options) : IHostedService
{
    private readonly AppSeedOptions _options = options.Value;


    /// <inheritdoc />
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        if (!_options.Enabled)
        {
            logger.LogInformation("AppSeed 未启用，跳过业务数据初始化");
            return;
        }

        using var scope = serviceProvider.CreateScope();
        var appDbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
        var dictionaryDbContext = scope.ServiceProvider.GetRequiredService<DictionaryDbContext>();

        var defaultTenantId = await EnsureDefaultTenantAsync(appDbContext, cancellationToken);
        await EnsureDictionarySeedsAsync(dictionaryDbContext, defaultTenantId, cancellationToken);

        logger.LogInformation("AppSeed 完成业务数据初始化");
    }

    /// <inheritdoc />
    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

    /// <summary>
    /// 确保默认租户存在。
    /// </summary>
    private async Task<long?> EnsureDefaultTenantAsync(TakeoutAppDbContext dbContext, CancellationToken cancellationToken)
    {
        var tenantOptions = _options.DefaultTenant;
        if (tenantOptions == null || string.IsNullOrWhiteSpace(tenantOptions.Code) || string.IsNullOrWhiteSpace(tenantOptions.Name))
        {
            logger.LogInformation("AppSeed 未配置默认租户，跳过租户种子");
            return null;
        }

        var code = tenantOptions.Code.Trim();
        var existingTenant = await dbContext.Tenants
            .IgnoreQueryFilters()
            .FirstOrDefaultAsync(x => x.Code == code, cancellationToken);

        if (existingTenant == null)
        {
            var tenant = new Tenant
            {
                Id = tenantOptions.TenantId,
                Code = code,
                Name = tenantOptions.Name.Trim(),
                ShortName = tenantOptions.ShortName?.Trim(),
                ContactName = tenantOptions.ContactName?.Trim(),
                ContactPhone = tenantOptions.ContactPhone?.Trim(),
                Status = TenantStatus.Active
            };

            await dbContext.Tenants.AddAsync(tenant, cancellationToken);
            await dbContext.SaveChangesAsync(cancellationToken);
            logger.LogInformation("AppSeed 已创建默认租户 {TenantCode}", code);
            return tenant.Id;
        }

        var updated = false;

        if (!string.Equals(existingTenant.Name, tenantOptions.Name, StringComparison.Ordinal))
        {
            existingTenant.Name = tenantOptions.Name.Trim();
            updated = true;
        }

        if (!string.Equals(existingTenant.ShortName, tenantOptions.ShortName, StringComparison.Ordinal))
        {
            existingTenant.ShortName = tenantOptions.ShortName?.Trim();
            updated = true;
        }

        if (!string.Equals(existingTenant.ContactName, tenantOptions.ContactName, StringComparison.Ordinal))
        {
            existingTenant.ContactName = tenantOptions.ContactName?.Trim();
            updated = true;
        }

        if (!string.Equals(existingTenant.ContactPhone, tenantOptions.ContactPhone, StringComparison.Ordinal))
        {
            existingTenant.ContactPhone = tenantOptions.ContactPhone?.Trim();
            updated = true;
        }

        if (existingTenant.Status != TenantStatus.Active)
        {
            existingTenant.Status = TenantStatus.Active;
            updated = true;
        }

        if (updated)
        {
            dbContext.Tenants.Update(existingTenant);
            await dbContext.SaveChangesAsync(cancellationToken);
            logger.LogInformation("AppSeed 已更新默认租户 {TenantCode}", code);
        }
        else
        {
            logger.LogInformation("AppSeed 默认租户 {TenantCode} 已存在且无需更新", code);
        }

        return existingTenant.Id;
    }

    /// <summary>
    /// 确保基础字典存在。
    /// </summary>
    private async Task EnsureDictionarySeedsAsync(DictionaryDbContext dbContext, long? defaultTenantId, CancellationToken cancellationToken)
    {
        var dictionaryGroups = _options.DictionaryGroups ?? new List<DictionarySeedGroupOptions>();
        var hasDictionaryGroups = dictionaryGroups.Count > 0;

        if (!hasDictionaryGroups)
        {
            logger.LogInformation("AppSeed 未配置基础字典，跳过字典种子");
        }

        if (hasDictionaryGroups)
        {
            foreach (var groupOptions in dictionaryGroups)
            {
                if (string.IsNullOrWhiteSpace(groupOptions.Code) || string.IsNullOrWhiteSpace(groupOptions.Name))
                {
                    logger.LogWarning("AppSeed 跳过字典分组，Code 或 Name 为空");
                    continue;
                }

                var tenantId = groupOptions.TenantId ?? defaultTenantId ?? 0;
                var code = groupOptions.Code.Trim();

                var group = await dbContext.DictionaryGroups
                    .IgnoreQueryFilters()
                    .FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Code == code, cancellationToken);

                if (group == null)
                {
                    group = new DictionaryGroup
                    {
                        Id = 0,
                        TenantId = tenantId,
                        Code = code,
                        Name = groupOptions.Name.Trim(),
                        Scope = groupOptions.Scope,
                        Description = groupOptions.Description?.Trim(),
                        IsEnabled = groupOptions.IsEnabled
                    };

                    await dbContext.DictionaryGroups.AddAsync(group, cancellationToken);
                    logger.LogInformation("AppSeed 创建字典分组 {GroupCode} (Tenant: {TenantId})", code, tenantId);
                }
                else
                {
                    var groupUpdated = false;

                    if (!string.Equals(group.Name, groupOptions.Name, StringComparison.Ordinal))
                    {
                        group.Name = groupOptions.Name.Trim();
                        groupUpdated = true;
                    }

                    if (!string.Equals(group.Description, groupOptions.Description, StringComparison.Ordinal))
                    {
                        group.Description = groupOptions.Description?.Trim();
                        groupUpdated = true;
                    }

                    if (group.Scope != groupOptions.Scope)
                    {
                        group.Scope = groupOptions.Scope;
                        groupUpdated = true;
                    }

                    if (group.IsEnabled != groupOptions.IsEnabled)
                    {
                        group.IsEnabled = groupOptions.IsEnabled;
                        groupUpdated = true;
                    }

                    if (groupUpdated)
                    {
                        dbContext.DictionaryGroups.Update(group);
                    }
                }

                await UpsertDictionaryItemsAsync(dbContext, group, groupOptions.Items, tenantId, cancellationToken);
            }
        }

        await EnsureSystemParametersAsync(dbContext, defaultTenantId, cancellationToken);
        await dbContext.SaveChangesAsync(cancellationToken);
    }


    /// <summary>
    /// 确保系统参数以独立表形式可重复种子。
    /// </summary>
    private async Task EnsureSystemParametersAsync(DictionaryDbContext dbContext, long? defaultTenantId, CancellationToken cancellationToken)
    {
        var systemParameters = _options.SystemParameters ?? new List<SystemParameterSeedOptions>();

        if (systemParameters.Count == 0)
        {
            logger.LogInformation("AppSeed 未配置系统参数，跳过系统参数种子");
            return;
        }

        var grouped = systemParameters
            .Where(x => !string.IsNullOrWhiteSpace(x.Key) && !string.IsNullOrWhiteSpace(x.Value))
            .GroupBy(x => x.TenantId ?? defaultTenantId ?? 0);

        if (!grouped.Any())
        {
            logger.LogInformation("AppSeed 系统参数配置为空，跳过系统参数种子");
            return;
        }

        foreach (var group in grouped)
        {
            var tenantId = group.Key;
            var existingParameters = await dbContext.SystemParameters
                .IgnoreQueryFilters()
                .Where(x => x.TenantId == tenantId)
                .ToListAsync(cancellationToken);

            foreach (var seed in group)
            {
                var key = seed.Key.Trim();
                var existing = existingParameters.FirstOrDefault(x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase));

                if (existing == null)
                {
                    var parameter = new SystemParameter
                    {
                        Id = 0,
                        TenantId = tenantId,
                        Key = key,
                        Value = seed.Value.Trim(),
                        Description = seed.Description?.Trim(),
                        SortOrder = seed.SortOrder,
                        IsEnabled = seed.IsEnabled
                    };

                    await dbContext.SystemParameters.AddAsync(parameter, cancellationToken);
                    continue;
                }

                var updated = false;

                if (!string.Equals(existing.Value, seed.Value, StringComparison.Ordinal))
                {
                    existing.Value = seed.Value.Trim();
                    updated = true;
                }

                if (!string.Equals(existing.Description, seed.Description, StringComparison.Ordinal))
                {
                    existing.Description = seed.Description?.Trim();
                    updated = true;
                }

                if (existing.SortOrder != seed.SortOrder)
                {
                    existing.SortOrder = seed.SortOrder;
                    updated = true;
                }

                if (existing.IsEnabled != seed.IsEnabled)
                {
                    existing.IsEnabled = seed.IsEnabled;
                    updated = true;
                }

                if (updated)
                {
                    dbContext.SystemParameters.Update(existing);
                }
            }
        }
    }

    /// <summary>
    /// 合并字典项。
    /// </summary>
    private static async Task UpsertDictionaryItemsAsync(
        DictionaryDbContext dbContext,
        DictionaryGroup group,
        IEnumerable<DictionarySeedItemOptions> seedItems,
        long tenantId,
        CancellationToken cancellationToken)
    {
        // 确保分组已持久化以获取正确的主键，避免 FK 约束报错。
        if (!dbContext.Entry(group).IsKeySet || group.Id == 0)
        {
            await dbContext.SaveChangesAsync(cancellationToken);
        }

        var materializedItems = seedItems
            .Where(item => !string.IsNullOrWhiteSpace(item.Key) && !string.IsNullOrWhiteSpace(item.Value))
            .ToList();

        if (materializedItems.Count == 0)
        {
            return;
        }

        var existingItems = await dbContext.DictionaryItems
            .IgnoreQueryFilters()
            .Where(x => x.GroupId == group.Id)
            .ToListAsync(cancellationToken);

        foreach (var seed in materializedItems)
        {
            var key = seed.Key.Trim();
            var existing = existingItems.FirstOrDefault(x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase));

            if (existing == null)
            {
                var newItem = new DictionaryItem
                {
                    Id = 0,
                    TenantId = tenantId,
                    GroupId = group.Id,
                    Key = key,
                    Value = seed.Value.Trim(),
                    Description = seed.Description?.Trim(),
                    SortOrder = seed.SortOrder,
                    IsEnabled = seed.IsEnabled
                };

                await dbContext.DictionaryItems.AddAsync(newItem, cancellationToken);
                continue;
            }

            var updated = false;

            if (!string.Equals(existing.Value, seed.Value, StringComparison.Ordinal))
            {
                existing.Value = seed.Value.Trim();
                updated = true;
            }

            if (!string.Equals(existing.Description, seed.Description, StringComparison.Ordinal))
            {
                existing.Description = seed.Description?.Trim();
                updated = true;
            }

            if (existing.SortOrder != seed.SortOrder)
            {
                existing.SortOrder = seed.SortOrder;
                updated = true;
            }

            if (existing.IsEnabled != seed.IsEnabled)
            {
                existing.IsEnabled = seed.IsEnabled;
                updated = true;
            }

            if (updated)
            {
                dbContext.DictionaryItems.Update(existing);
            }
        }
    }
}
