using System.Globalization;
using System.IO;
using System.Text;
using CsvHelper;
using CsvHelper.Configuration;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Localization;

namespace SharepointToolbox.Services.Export;

/// <summary>
/// Exports the failed subset of a <see cref="BulkOperationSummary{T}"/> run
/// to CSV. CsvHelper is used so the <typeparamref name="T"/> payload's
/// properties become columns automatically, plus one error-message and one
/// timestamp column appended at the end.
/// </summary>
public class BulkResultCsvExportService
{
    private static readonly CsvConfiguration CsvConfig = new(CultureInfo.InvariantCulture)
    {
        // Prevent CSV formula injection: prefix =, +, -, @, tab, CR with single quote
        InjectionOptions = InjectionOptions.Escape,
    };

    /// <summary>
    /// Builds a CSV containing only items whose <see cref="BulkItemResult{T}.IsSuccess"/>
    /// is <c>false</c>. Columns: every public property of <typeparamref name="T"/>
    /// followed by Error and Timestamp (ISO-8601).
    /// </summary>
    public string BuildFailedItemsCsv<T>(IReadOnlyList<BulkItemResult<T>> failedItems)
    {
        var TL = TranslationSource.Instance;
        using var writer = new StringWriter();
        using var csv = new CsvWriter(writer, CsvConfig);

        csv.WriteHeader<T>();
        csv.WriteField(TL["report.col.error"]);
        csv.WriteField(TL["report.col.timestamp"]);
        csv.NextRecord();

        foreach (var item in failedItems.Where(r => !r.IsSuccess))
        {
            csv.WriteRecord(item.Item);
            csv.WriteField(item.ErrorMessage);
            csv.WriteField(item.Timestamp.ToString("o"));
            csv.NextRecord();
        }

        return writer.ToString();
    }

    /// <summary>Writes the failed-items CSV to <paramref name="filePath"/> with UTF-8 BOM.</summary>
    public async Task WriteFailedItemsCsvAsync<T>(
        IReadOnlyList<BulkItemResult<T>> failedItems,
        string filePath,
        CancellationToken ct)
    {
        var content = BuildFailedItemsCsv(failedItems);
        await ExportFileWriter.WriteCsvAsync(filePath, content, ct);
    }
}
