using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using System.Globalization;
using TakeoutSaaS.Domain.Common.Enums;
using TakeoutSaaS.Domain.Merchants.Entities;
using TakeoutSaaS.Domain.Merchants.Enums;
using TakeoutSaaS.Domain.Merchants.Services;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Enums;

namespace TakeoutSaaS.Infrastructure.App.Services;

/// <summary>
/// 商户导出服务实现（PDF）。
/// </summary>
public sealed class MerchantExportService : IMerchantExportService
{
    public MerchantExportService()
    {
        QuestPDF.Settings.License = LicenseType.Community;
    }

    /// <inheritdoc />
    public Task<byte[]> ExportToPdfAsync(
        Merchant merchant,
        string? tenantName,
        IReadOnlyList<Store> stores,
        IReadOnlyList<MerchantAuditLog> auditLogs,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(merchant);

        var safeStores = stores ?? Array.Empty<Store>();
        var safeAuditLogs = auditLogs ?? Array.Empty<MerchantAuditLog>();

        var document = Document.Create(container =>
        {
            container.Page(page =>
            {
                page.Size(PageSizes.A4);
                page.Margin(24);
                page.DefaultTextStyle(x => x.FontSize(10));

                page.Content().Column(column =>
                {
                    column.Spacing(10);
                    column.Item().Text("Merchant Export").FontSize(16).SemiBold();

                    column.Item().Element(section => BuildBasicSection(section, merchant, tenantName));
                    column.Item().Element(section => BuildStoresSection(section, safeStores, cancellationToken));
                    column.Item().Element(section => BuildAuditSection(section, safeAuditLogs, cancellationToken));
                });
            });
        });

        return Task.FromResult(document.GeneratePdf());
    }

    private static void BuildBasicSection(IContainer container, Merchant merchant, string? tenantName)
    {
        container.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(10).Column(column =>
        {
            column.Spacing(4);
            column.Item().Text("Basic Information").SemiBold();
            column.Item().Text($"Merchant: {merchant.BrandName}");
            column.Item().Text($"Tenant: {tenantName ?? "-"} (ID: {merchant.TenantId})");
            column.Item().Text($"Operating Mode: {ResolveOperatingMode(merchant.OperatingMode)}");
            column.Item().Text($"Status: {merchant.Status}");
            column.Item().Text($"Frozen: {(merchant.IsFrozen ? "Yes" : "No")}");
            column.Item().Text($"License Number: {merchant.BusinessLicenseNumber ?? "-"}");
            column.Item().Text($"Legal Representative: {merchant.LegalPerson ?? "-"}");
            column.Item().Text($"Registered Address: {merchant.Address ?? "-"}");
            column.Item().Text($"Contact Phone: {merchant.ContactPhone}");
            column.Item().Text($"Contact Email: {merchant.ContactEmail ?? "-"}");
            column.Item().Text($"Approved At: {FormatDateTime(merchant.ApprovedAt)}");
            column.Item().Text($"Approved By: {merchant.ApprovedBy?.ToString() ?? "-"}");
        });
    }

    private static void BuildStoresSection(IContainer container, IReadOnlyList<Store> stores, CancellationToken cancellationToken)
    {
        container.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(10).Column(column =>
        {
            column.Spacing(4);
            column.Item().Text("Stores").SemiBold();

            if (stores.Count == 0)
            {
                column.Item().Text("No stores.");
                return;
            }

            for (var i = 0; i < stores.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var store = stores[i];
                column.Item().Text($"{i + 1}. {store.Name} | {ResolveStoreStatus(store.Status)} | {store.Address ?? "-"} | {store.Phone ?? "-"}");
            }
        });
    }

    private static void BuildAuditSection(IContainer container, IReadOnlyList<MerchantAuditLog> auditLogs, CancellationToken cancellationToken)
    {
        container.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(10).Column(column =>
        {
            column.Spacing(4);
            column.Item().Text("Audit History").SemiBold();

            if (auditLogs.Count == 0)
            {
                column.Item().Text("No audit records.");
                return;
            }

            for (var i = 0; i < auditLogs.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var log = auditLogs[i];
                var title = string.IsNullOrWhiteSpace(log.Title) ? log.Action.ToString() : log.Title;
                column.Item().Text($"{i + 1}. {title} | {log.OperatorName ?? "-"} | {FormatDateTime(log.CreatedAt)}");
                if (!string.IsNullOrWhiteSpace(log.Description))
                {
                    column.Item().Text($"   {log.Description}");
                }
            }
        });
    }

    private static string ResolveOperatingMode(OperatingMode? mode)
        => mode switch
        {
            OperatingMode.SameEntity => "SameEntity",
            OperatingMode.DifferentEntity => "DifferentEntity",
            _ => "-"
        };

    private static string ResolveStoreStatus(StoreStatus status)
        => status switch
        {
            StoreStatus.Closed => "Closed",
            StoreStatus.Preparing => "Preparing",
            StoreStatus.Operating => "Operating",
            StoreStatus.Suspended => "Suspended",
            _ => status.ToString()
        };

    private static string FormatDateTime(DateTime? value)
        => value.HasValue ? value.Value.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture) : "-";
}
