using SharepointToolbox.Core.Models;
using SharepointToolbox.Localization;
using System.Text;

namespace SharepointToolbox.Services.Export;

/// <summary>
/// Exports DuplicateGroup list to a self-contained HTML with collapsible group cards.
/// Port of PS Export-DuplicatesToHTML (PS lines 2235-2406).
/// Each group gets a card showing item count badge and a table of paths.
/// </summary>
public class DuplicatesHtmlExportService
{
    /// <summary>
    /// Builds a self-contained HTML string rendering one collapsible card per
    /// <see cref="DuplicateGroup"/>. The document ships with inline CSS and a
    /// tiny JS toggle so no external assets are needed.
    /// </summary>
    public string BuildHtml(IReadOnlyList<DuplicateGroup> groups, ReportBranding? branding = null)
    {
        var T = TranslationSource.Instance;
        var sb = new StringBuilder();

        sb.AppendLine("<!DOCTYPE html>");
        sb.AppendLine("<html lang=\"en\">");
        sb.AppendLine("<head>");
        sb.AppendLine("<meta charset=\"UTF-8\">");
        sb.AppendLine("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">");
        sb.AppendLine($"<title>{T["report.title.duplicates"]}</title>");
        sb.AppendLine("""
            <style>
              body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 13px; margin: 20px; background: #f5f5f5; }
              h1 { color: #0078d4; }
              .summary { margin-bottom: 16px; font-size: 12px; color: #444; }
              .group-card { background: #fff; border: 1px solid #ddd; border-radius: 6px;
                            margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,.1); overflow: hidden; }
              .group-header { background: #0078d4; color: #fff; padding: 8px 14px;
                              display: flex; align-items: center; justify-content: space-between;
                              cursor: pointer; user-select: none; }
              .group-header:hover { background: #106ebe; }
              .group-name { font-weight: 600; font-size: 14px; }
              .badge { display: inline-block; padding: 2px 8px; border-radius: 10px;
                       font-size: 11px; font-weight: 700; }
              .badge-dup  { background: #e53935; color: #fff; }
              .group-body { padding: 0; }
              table { width: 100%; border-collapse: collapse; }
              th { background: #f0f7ff; color: #333; padding: 6px 12px; text-align: left;
                   font-weight: 600; border-bottom: 1px solid #ddd; font-size: 12px; }
              td { padding: 5px 12px; border-bottom: 1px solid #eee; font-size: 12px; word-break: break-all; }
              tr:last-child td { border-bottom: none; }
              .collapsed { display: none; }
              .generated { font-size: 11px; color: #888; margin-top: 16px; }
            </style>
            <script>
              function toggleGroup(id) {
                var body = document.getElementById('gb-' + id);
                if (body) body.classList.toggle('collapsed');
              }
            </script>
            </head>
            <body>
            """);
        sb.Append(BrandingHtmlHelper.BuildBrandingHeader(branding));
        sb.AppendLine($"<h1>{T["report.title.duplicates_short"]}</h1>");

        sb.AppendLine($"<p class=\"summary\">{groups.Count:N0} {T["report.text.duplicate_groups_found"]}</p>");

        for (int i = 0; i < groups.Count; i++)
        {
            var g = groups[i];
            int count = g.Items.Count;
            string badgeClass = "badge-dup";

            sb.AppendLine($"""
                <div class="group-card">
                  <div class="group-header" onclick="toggleGroup({i})">
                    <span class="group-name">{H(g.Name)}</span>
                    <span class="badge {badgeClass}">{count} {T["report.text.copies"]}</span>
                  </div>
                  <div class="group-body" id="gb-{i}">
                    <table>
                      <thead>
                        <tr>
                          <th>{T["report.col.number"]}</th>
                          <th>{T["report.col.name"]}</th>
                          <th>{T["report.col.library"]}</th>
                          <th>{T["report.col.path"]}</th>
                          <th>{T["report.col.size"]}</th>
                          <th>{T["report.col.created"]}</th>
                          <th>{T["report.col.modified"]}</th>
                        </tr>
                      </thead>
                      <tbody>
                """);

            for (int j = 0; j < g.Items.Count; j++)
            {
                var item = g.Items[j];
                string size     = item.SizeBytes.HasValue ? FormatSize(item.SizeBytes.Value) : string.Empty;
                string created  = item.Created.HasValue  ? item.Created.Value.ToString("yyyy-MM-dd")  : string.Empty;
                string modified = item.Modified.HasValue ? item.Modified.Value.ToString("yyyy-MM-dd") : string.Empty;

                sb.AppendLine($"""
                          <tr>
                            <td>{j + 1}</td>
                            <td>{H(item.Name)}</td>
                            <td>{H(item.Library)}</td>
                            <td><a href="{H(item.Path)}" target="_blank">{H(item.Path)}</a></td>
                            <td>{size}</td>
                            <td>{created}</td>
                            <td>{modified}</td>
                          </tr>
                    """);
            }

            sb.AppendLine("""
                      </tbody>
                    </table>
                  </div>
                </div>
                """);
        }

        sb.AppendLine($"<p class=\"generated\">{T["report.text.generated_colon"]} {DateTime.Now:yyyy-MM-dd HH:mm}</p>");
        sb.AppendLine("</body></html>");

        return sb.ToString();
    }

    /// <summary>Writes the HTML report to the specified file path using UTF-8.</summary>
    public async Task WriteAsync(IReadOnlyList<DuplicateGroup> groups, string filePath, CancellationToken ct, ReportBranding? branding = null)
    {
        var html = BuildHtml(groups, branding);
        await System.IO.File.WriteAllTextAsync(filePath, html, Encoding.UTF8, ct);
    }

    /// <summary>
    /// Writes one or more HTML reports depending on <paramref name="splitMode"/> and
    /// <paramref name="layout"/>. Single → one file. BySite + SeparateFiles → one
    /// file per site. BySite + SingleTabbed → one file with per-site iframe tabs.
    /// </summary>
    public async Task WriteAsync(
        IReadOnlyList<DuplicateGroup> groups,
        string basePath,
        ReportSplitMode splitMode,
        HtmlSplitLayout layout,
        CancellationToken ct,
        ReportBranding? branding = null)
    {
        if (splitMode != ReportSplitMode.BySite)
        {
            await WriteAsync(groups, basePath, ct, branding);
            return;
        }

        var partitions = DuplicatesCsvExportService.PartitionBySite(groups).ToList();

        if (layout == HtmlSplitLayout.SingleTabbed)
        {
            var parts = partitions
                .Select(p => (p.Label, Html: BuildHtml(p.Partition, branding)))
                .ToList();
            var T = TranslationSource.Instance;
            var tabbed = ReportSplitHelper.BuildTabbedHtml(parts, T["report.title.duplicates_short"]);
            await System.IO.File.WriteAllTextAsync(basePath, tabbed, Encoding.UTF8, ct);
            return;
        }

        foreach (var partition in partitions)
        {
            ct.ThrowIfCancellationRequested();
            var path = ReportSplitHelper.BuildPartitionPath(basePath, partition.Label);
            await WriteAsync(partition.Partition, path, ct, branding);
        }
    }

    private static string H(string value) =>
        System.Net.WebUtility.HtmlEncode(value ?? string.Empty);

    private static string FormatSize(long bytes)
    {
        if (bytes >= 1_073_741_824L) return $"{bytes / 1_073_741_824.0:F2} GB";
        if (bytes >= 1_048_576L)     return $"{bytes / 1_048_576.0:F2} MB";
        if (bytes >= 1024L)          return $"{bytes / 1024.0:F2} KB";
        return $"{bytes} B";
    }
}
