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

namespace SharepointToolbox.Services.Export;

/// <summary>
/// Exports permission entries to a self-contained interactive HTML report.
/// Ports PowerShell Export-PermissionsToHTML functionality.
/// No external CSS/JS dependencies — everything is inline.
/// </summary>
public class HtmlExportService
{
    /// <summary>
    /// Builds a self-contained HTML string from the supplied permission entries.
    /// Includes inline CSS, inline JS filter, stats cards, type badges, unique/inherited badges, and user pills.
    /// </summary>
    public string BuildHtml(IReadOnlyList<PermissionEntry> entries)
    {
        // Compute stats
        var totalEntries      = entries.Count;
        var uniquePermSets    = entries.Select(e => e.PermissionLevels).Distinct().Count();
        var distinctUsers     = entries
            .SelectMany(e => e.UserLogins.Split(';', StringSplitOptions.RemoveEmptyEntries))
            .Select(u => u.Trim())
            .Where(u => u.Length > 0)
            .Distinct()
            .Count();

        var sb = new StringBuilder();

        // ── HTML HEAD ──────────────────────────────────────────────────────────
        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>SharePoint Permissions Report</title>");
        sb.AppendLine("<style>");
        sb.AppendLine(@"
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; }
h1 { padding: 20px 24px 10px; font-size: 1.5rem; color: #1a1a2e; }
.stats { display: flex; gap: 16px; padding: 0 24px 16px; flex-wrap: wrap; }
.stat-card { background: #fff; border-radius: 8px; padding: 14px 20px; min-width: 160px; box-shadow: 0 1px 4px rgba(0,0,0,.1); }
.stat-card .value { font-size: 2rem; font-weight: 700; color: #1a1a2e; }
.stat-card .label { font-size: .8rem; color: #666; margin-top: 2px; }
.filter-wrap { padding: 0 24px 12px; }
#filter { width: 320px; padding: 8px 12px; border: 1px solid #ccc; border-radius: 6px; font-size: .95rem; }
.table-wrap { overflow-x: auto; padding: 0 24px 32px; }
table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,.1); }
th { background: #1a1a2e; color: #fff; padding: 10px 14px; text-align: left; font-size: .85rem; white-space: nowrap; }
td { padding: 9px 14px; border-bottom: 1px solid #eee; vertical-align: top; font-size: .875rem; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: #fafafa; }
/* Type badges */
.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: .75rem; font-weight: 600; white-space: nowrap; }
.badge.site-coll { background: #dbeafe; color: #1e40af; }
.badge.site      { background: #dcfce7; color: #166534; }
.badge.list      { background: #fef9c3; color: #854d0e; }
.badge.folder    { background: #f3f4f6; color: #374151; }
/* Unique/Inherited badges */
.badge.unique    { background: #dcfce7; color: #166534; }
.badge.inherited { background: #f3f4f6; color: #374151; }
/* User pills */
.user-pill { display: inline-block; background: #e0e7ff; color: #3730a3; border-radius: 12px; padding: 2px 10px; font-size: .75rem; margin: 2px 3px 2px 0; white-space: nowrap; }
.user-pill.external-user { background: #fff7ed; color: #9a3412; border: 1px solid #fed7aa; }
a { color: #2563eb; text-decoration: none; }
a:hover { text-decoration: underline; }
");
        sb.AppendLine("</style>");
        sb.AppendLine("</head>");

        // ── BODY ───────────────────────────────────────────────────────────────
        sb.AppendLine("<body>");
        sb.AppendLine("<h1>SharePoint Permissions Report</h1>");

        // Stats cards
        sb.AppendLine("<div class=\"stats\">");
        sb.AppendLine($"  <div class=\"stat-card\"><div class=\"value\">{totalEntries}</div><div class=\"label\">Total Entries</div></div>");
        sb.AppendLine($"  <div class=\"stat-card\"><div class=\"value\">{uniquePermSets}</div><div class=\"label\">Unique Permission Sets</div></div>");
        sb.AppendLine($"  <div class=\"stat-card\"><div class=\"value\">{distinctUsers}</div><div class=\"label\">Distinct Users/Groups</div></div>");
        sb.AppendLine("</div>");

        // Filter input
        sb.AppendLine("<div class=\"filter-wrap\">");
        sb.AppendLine("  <input type=\"text\" id=\"filter\" placeholder=\"Filter permissions...\" onkeyup=\"filterTable()\" />");
        sb.AppendLine("</div>");

        // Table
        sb.AppendLine("<div class=\"table-wrap\">");
        sb.AppendLine("<table id=\"permTable\">");
        sb.AppendLine("<thead><tr>");
        sb.AppendLine("  <th>Object</th><th>Title</th><th>URL</th><th>Unique</th><th>Users/Groups</th><th>Permission Level</th><th>Granted Through</th>");
        sb.AppendLine("</tr></thead>");
        sb.AppendLine("<tbody>");

        foreach (var entry in entries)
        {
            var typeCss   = ObjectTypeCss(entry.ObjectType);
            var uniqueCss = entry.HasUniquePermissions ? "badge unique" : "badge inherited";
            var uniqueLbl = entry.HasUniquePermissions ? "Unique" : "Inherited";

            // Build user pills: zip UserLogins and Users (both semicolon-delimited)
            var logins = entry.UserLogins.Split(';', StringSplitOptions.RemoveEmptyEntries);
            var names  = entry.Users.Split(';', StringSplitOptions.RemoveEmptyEntries);
            var pillsBuilder = new StringBuilder();
            for (int i = 0; i < logins.Length; i++)
            {
                var login = logins[i].Trim();
                var name  = i < names.Length ? names[i].Trim() : login;
                var isExt = login.Contains("#EXT#", StringComparison.OrdinalIgnoreCase);
                var pillCss = isExt ? "user-pill external-user" : "user-pill";
                pillsBuilder.Append($"<span class=\"{pillCss}\" data-email=\"{HtmlEncode(login)}\">{HtmlEncode(name)}</span>");
            }

            sb.AppendLine("<tr>");
            sb.AppendLine($"  <td><span class=\"{typeCss}\">{HtmlEncode(entry.ObjectType)}</span></td>");
            sb.AppendLine($"  <td>{HtmlEncode(entry.Title)}</td>");
            sb.AppendLine($"  <td><a href=\"{HtmlEncode(entry.Url)}\" target=\"_blank\">Link</a></td>");
            sb.AppendLine($"  <td><span class=\"{uniqueCss}\">{uniqueLbl}</span></td>");
            sb.AppendLine($"  <td>{pillsBuilder}</td>");
            sb.AppendLine($"  <td>{HtmlEncode(entry.PermissionLevels)}</td>");
            sb.AppendLine($"  <td>{HtmlEncode(entry.GrantedThrough)}</td>");
            sb.AppendLine("</tr>");
        }

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

        // Inline JS
        sb.AppendLine("<script>");
        sb.AppendLine(@"function filterTable() {
  var input = document.getElementById('filter').value.toLowerCase();
  var rows = document.querySelectorAll('#permTable tbody tr');
  rows.forEach(function(row) {
    row.style.display = row.textContent.toLowerCase().indexOf(input) > -1 ? '' : 'none';
  });
}");
        sb.AppendLine("</script>");
        sb.AppendLine("</body>");
        sb.AppendLine("</html>");

        return sb.ToString();
    }

    /// <summary>
    /// Writes the HTML report to the specified file path using UTF-8 without BOM.
    /// </summary>
    public async Task WriteAsync(IReadOnlyList<PermissionEntry> entries, string filePath, CancellationToken ct)
    {
        var html = BuildHtml(entries);
        await File.WriteAllTextAsync(filePath, html, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), ct);
    }

    /// <summary>Returns the CSS class for the object-type badge.</summary>
    private static string ObjectTypeCss(string t) => t switch
    {
        "Site Collection" => "badge site-coll",
        "Site"            => "badge site",
        "List"            => "badge list",
        "Folder"          => "badge folder",
        _                 => "badge"
    };

    /// <summary>Minimal HTML encoding for text content and attribute values.</summary>
    private static string HtmlEncode(string value)
    {
        if (string.IsNullOrEmpty(value)) return string.Empty;
        return value
            .Replace("&",  "&amp;")
            .Replace("<",  "&lt;")
            .Replace(">",  "&gt;")
            .Replace("\"", "&quot;")
            .Replace("'",  "&#39;");
    }
}
