using CsvHelper;

using FabApprovalWorkerService.Models;

using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;

namespace FabApprovalWorkerService.Services;

public interface ITrainingRecordService {
    IEnumerable<TrainingRecord> ScrapeRecordsFromCsvFile(CsvReader csvReader);
    ConcurrentDictionary<(string, string), TrainingRecord> SortAndFilterTrainingRecordsByCompletionDate(IEnumerable<TrainingRecord> trainingRecords);
}
public class TrainingRecordService {
    private readonly ILogger<TrainingRecordService> _logger;

    public TrainingRecordService(ILogger<TrainingRecordService> logger) {
        _logger = logger;
        if (_logger is null) throw new ArgumentNullException("ILogger not injected");
    }

    public IEnumerable<TrainingRecord> ScrapeTrainingRecordsFromCsvFile([DisallowNull] CsvReader csvReader) {
        if (csvReader is null) throw new ArgumentNullException("csvReader cannot be null");

        try {
            _logger.LogInformation("Attempting to scrape training records from CSV file");

            using (csvReader) {
                return csvReader.GetRecords<TrainingRecord>();
            }
        } catch (Exception ex) {
            _logger.LogError("An exception occurred when attempting to scrape training records from CSV file. Exception: {ex}",
                             ex.Message);

            throw;
        }
    }

    public ConcurrentDictionary<(string, string), TrainingRecord> SortAndFilterTrainingRecordsByCompletionDate([DisallowNull] IEnumerable<TrainingRecord> trainingRecords) {
        if (trainingRecords is null) throw new ArgumentNullException("trainingRecords cannot be null");

        ConcurrentDictionary<(string, string), TrainingRecord> recordsMap = new();

        try {
            _logger.LogInformation("Attempting to sort and filter training records");
            
            IOrderedEnumerable<TrainingRecord> sortedRecords = trainingRecords.OrderByDescending(t => t.UserId)
                                                                              .ThenBy(t => t.ItemId)
                                                                              .ThenByDescending(t => t.CompletionDate);

            foreach (TrainingRecord trainingRecord in sortedRecords) {
                if (!recordsMap.TryGetValue((trainingRecord.FirstName + trainingRecord.LastName, trainingRecord.ItemId), out TrainingRecord? existingRecord)) {
                    recordsMap[(trainingRecord.FirstName + trainingRecord.LastName, trainingRecord.ItemId)] = trainingRecord;
                }
            }

            return recordsMap;
        } catch (Exception ex) {
            _logger.LogError("An exception occurred when attempting to sort and filter training records. Exception: {ex}", ex.Message);

            return recordsMap;
        }
    }
}
