using ClosedXML.Excel;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using System.Globalization;
using TakeoutSaaS.Domain.Finance.Enums;
using TakeoutSaaS.Domain.Finance.Models;
using TakeoutSaaS.Domain.Finance.Services;

namespace TakeoutSaaS.Infrastructure.App.Services;

/// <summary>
/// 经营报表导出服务实现（PDF / Excel）。
/// </summary>
public sealed class FinanceBusinessReportExportService : IFinanceBusinessReportExportService
{
    public FinanceBusinessReportExportService()
    {
        QuestPDF.Settings.License = LicenseType.Community;
    }

    /// <inheritdoc />
    public Task<byte[]> ExportSinglePdfAsync(
        FinanceBusinessReportDetailSnapshot detail,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(detail);
        cancellationToken.ThrowIfCancellationRequested();
        return Task.FromResult(BuildPdf([detail]));
    }

    /// <inheritdoc />
    public Task<byte[]> ExportSingleExcelAsync(
        FinanceBusinessReportDetailSnapshot detail,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(detail);
        cancellationToken.ThrowIfCancellationRequested();

        using var workbook = new XLWorkbook();
        var worksheet = workbook.Worksheets.Add("经营报表");
        WriteDetailWorksheet(worksheet, detail);

        using var stream = new MemoryStream();
        workbook.SaveAs(stream);
        return Task.FromResult(stream.ToArray());
    }

    /// <inheritdoc />
    public Task<byte[]> ExportBatchPdfAsync(
        IReadOnlyList<FinanceBusinessReportDetailSnapshot> details,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(details);
        cancellationToken.ThrowIfCancellationRequested();
        return Task.FromResult(BuildPdf(details));
    }

    /// <inheritdoc />
    public Task<byte[]> ExportBatchExcelAsync(
        IReadOnlyList<FinanceBusinessReportDetailSnapshot> details,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(details);
        cancellationToken.ThrowIfCancellationRequested();

        using var workbook = new XLWorkbook();
        var summary = workbook.Worksheets.Add("汇总");
        WriteSummaryWorksheet(summary, details);

        for (var index = 0; index < details.Count; index++)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var detail = details[index];
            var sheetName = $"报表{index + 1:D2}";
            var worksheet = workbook.Worksheets.Add(sheetName);
            WriteDetailWorksheet(worksheet, detail);
        }

        using var stream = new MemoryStream();
        workbook.SaveAs(stream);
        return Task.FromResult(stream.ToArray());
    }

    private static byte[] BuildPdf(IReadOnlyList<FinanceBusinessReportDetailSnapshot> details)
    {
        var source = details.Count == 0
            ? [new FinanceBusinessReportDetailSnapshot()]
            : details;

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

                    page.Content().Column(column =>
                    {
                        column.Spacing(8);
                        column.Item().Text(BuildTitle(detail)).FontSize(16).SemiBold();
                        column.Item().Text($"状态：{ResolveStatusText(detail.Status)}");

                        column.Item().Element(section => BuildKpiSection(section, detail.Kpis));
                        column.Item().Element(section => BuildBreakdownSection(section, "收入明细（按渠道）", detail.IncomeBreakdowns));
                        column.Item().Element(section => BuildBreakdownSection(section, "成本明细（按类别）", detail.CostBreakdowns));
                    });
                });
            }
        });

        return document.GeneratePdf();
    }

    private static void BuildKpiSection(IContainer container, IReadOnlyList<FinanceBusinessReportKpiSnapshot> kpis)
    {
        container.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(10).Column(column =>
        {
            column.Spacing(4);
            column.Item().Text("关键指标").SemiBold();

            if (kpis.Count == 0)
            {
                column.Item().Text("暂无数据");
                return;
            }

            foreach (var item in kpis)
            {
                column.Item().Row(row =>
                {
                    row.RelativeItem().Text(item.Label);
                    row.RelativeItem().AlignRight().Text(FormatKpiValue(item.Key, item.Value));
                    row.RelativeItem().AlignRight().Text(
                        $"同比 {FormatSignedRate(item.YoyChangeRate)} | 环比 {FormatSignedRate(item.MomChangeRate)}");
                });
            }
        });
    }

    private static void BuildBreakdownSection(
        IContainer container,
        string title,
        IReadOnlyList<FinanceBusinessReportBreakdownSnapshot> rows)
    {
        container.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(10).Column(column =>
        {
            column.Spacing(4);
            column.Item().Text(title).SemiBold();

            if (rows.Count == 0)
            {
                column.Item().Text("暂无数据");
                return;
            }

            foreach (var item in rows)
            {
                column.Item().Row(row =>
                {
                    row.RelativeItem().Text(item.Label);
                    row.ConstantItem(80).AlignRight().Text(FormatPercent(item.Ratio));
                    row.ConstantItem(120).AlignRight().Text(FormatCurrency(item.Amount));
                });
            }
        });
    }

    private static void WriteSummaryWorksheet(
        IXLWorksheet worksheet,
        IReadOnlyList<FinanceBusinessReportDetailSnapshot> details)
    {
        worksheet.Cell(1, 1).Value = "报表标题";
        worksheet.Cell(1, 2).Value = "状态";
        worksheet.Cell(1, 3).Value = "营业额";
        worksheet.Cell(1, 4).Value = "订单数";
        worksheet.Cell(1, 5).Value = "客单价";
        worksheet.Cell(1, 6).Value = "退款率";
        worksheet.Cell(1, 7).Value = "成本总额";
        worksheet.Cell(1, 8).Value = "净利润";
        worksheet.Cell(1, 9).Value = "利润率";

        for (var index = 0; index < details.Count; index++)
        {
            var row = index + 2;
            var detail = details[index];
            worksheet.Cell(row, 1).Value = BuildTitle(detail);
            worksheet.Cell(row, 2).Value = ResolveStatusText(detail.Status);
            worksheet.Cell(row, 3).Value = detail.RevenueAmount;
            worksheet.Cell(row, 4).Value = detail.OrderCount;
            worksheet.Cell(row, 5).Value = detail.AverageOrderValue;
            worksheet.Cell(row, 6).Value = detail.RefundRate;
            worksheet.Cell(row, 7).Value = detail.CostTotalAmount;
            worksheet.Cell(row, 8).Value = detail.NetProfitAmount;
            worksheet.Cell(row, 9).Value = detail.ProfitRate;
        }

        worksheet.Columns().AdjustToContents();
    }

    private static void WriteDetailWorksheet(
        IXLWorksheet worksheet,
        FinanceBusinessReportDetailSnapshot detail)
    {
        var row = 1;

        worksheet.Cell(row, 1).Value = BuildTitle(detail);
        worksheet.Range(row, 1, row, 4).Merge().Style.Font.SetBold();
        row += 2;

        worksheet.Cell(row, 1).Value = "关键指标";
        worksheet.Cell(row, 1).Style.Font.SetBold();
        row += 1;

        worksheet.Cell(row, 1).Value = "指标";
        worksheet.Cell(row, 2).Value = "值";
        worksheet.Cell(row, 3).Value = "同比";
        worksheet.Cell(row, 4).Value = "环比";
        row += 1;

        foreach (var item in detail.Kpis)
        {
            worksheet.Cell(row, 1).Value = item.Label;
            worksheet.Cell(row, 2).Value = FormatKpiValue(item.Key, item.Value);
            worksheet.Cell(row, 3).Value = FormatSignedRate(item.YoyChangeRate);
            worksheet.Cell(row, 4).Value = FormatSignedRate(item.MomChangeRate);
            row += 1;
        }

        row += 1;
        row = WriteBreakdownTable(worksheet, row, "收入明细（按渠道）", detail.IncomeBreakdowns);
        row += 1;
        _ = WriteBreakdownTable(worksheet, row, "成本明细（按类别）", detail.CostBreakdowns);

        worksheet.Columns().AdjustToContents();
    }

    private static int WriteBreakdownTable(
        IXLWorksheet worksheet,
        int startRow,
        string title,
        IReadOnlyList<FinanceBusinessReportBreakdownSnapshot> rows)
    {
        var row = startRow;
        worksheet.Cell(row, 1).Value = title;
        worksheet.Cell(row, 1).Style.Font.SetBold();
        row += 1;

        worksheet.Cell(row, 1).Value = "名称";
        worksheet.Cell(row, 2).Value = "占比";
        worksheet.Cell(row, 3).Value = "金额";
        row += 1;

        foreach (var item in rows)
        {
            worksheet.Cell(row, 1).Value = item.Label;
            worksheet.Cell(row, 2).Value = FormatPercent(item.Ratio);
            worksheet.Cell(row, 3).Value = item.Amount;
            row += 1;
        }

        return row;
    }

    private static string FormatCurrency(decimal value) => $"¥{value:0.##}";
    private static string FormatPercent(decimal ratioValue) => $"{ratioValue * 100m:0.##}%";
    private static string FormatSignedRate(decimal rate) => $"{(rate >= 0m ? "+" : string.Empty)}{rate:0.##}%";
    private static string BuildTitle(FinanceBusinessReportDetailSnapshot detail) => detail.PeriodType switch
    {
        FinanceBusinessReportPeriodType.Daily => $"{detail.PeriodStartAt:yyyy年M月d日} 经营日报",
        FinanceBusinessReportPeriodType.Weekly => $"{detail.PeriodStartAt:yyyy年M月d日}~{detail.PeriodEndAt.AddDays(-1):M月d日} 经营周报",
        FinanceBusinessReportPeriodType.Monthly => $"{detail.PeriodStartAt:yyyy年M月} 经营月报",
        _ => detail.PeriodStartAt == default
            ? "经营报表"
            : detail.PeriodStartAt.ToString("yyyy-MM-dd 经营报表", CultureInfo.InvariantCulture)
    };
    private static string ResolveStatusText(FinanceBusinessReportStatus status) => status switch
    {
        FinanceBusinessReportStatus.Queued => "排队中",
        FinanceBusinessReportStatus.Running => "生成中",
        FinanceBusinessReportStatus.Succeeded => "已生成",
        FinanceBusinessReportStatus.Failed => "生成失败",
        _ => "未知"
    };

    private static string FormatKpiValue(string key, decimal value)
    {
        if (key == "order_count")
        {
            return $"{decimal.Round(value, 0, MidpointRounding.AwayFromZero):0}";
        }

        if (key is "refund_rate" or "profit_rate")
        {
            return $"{value * 100m:0.##}%";
        }

        return FormatCurrency(value);
    }
}
