/// <summary>
        /// Maps a the CSV employee model to the employee database model.
        /// </summary>
        /// <param name="employeeDto">CSV model from Transparent California.</param>
        /// <returns>Mapped employee entity.</returns>
        /// <exception cref="ArgumentNullException">Throws if DTO is null for validation.</exception>
        public static Employee ToEmployee(this TransparentCaliforniaCsvReadEmployeeDto employeeDto)
        {
            ArgumentValidation.CheckNotNull(employeeDto, nameof(employeeDto));

            string firstName  = string.Empty;
            string middleName = string.Empty;
            string lastName   = string.Empty;

            // Parse the employee name to persist
            var tokenizedName = employeeDto.EmployeeName?.Split(" ");

            if (!(tokenizedName is null))
            {
                switch (tokenizedName.Length)
                {
                case 1:
                    firstName = tokenizedName[0];
                    break;

                case 2:
                    firstName = tokenizedName[0];
                    lastName  = tokenizedName[1];
                    break;

                case 3:
                    firstName  = tokenizedName[0];
                    middleName = tokenizedName[1];
                    lastName   = tokenizedName[2];
                    break;
                }
            }

            return(new Employee
            {
                FirstName = firstName,
                MiddleName = middleName,
                LastName = lastName,
                JobTitle = employeeDto.JobTitle,
                BasePay = employeeDto.BasePay,
                OtherPay = employeeDto.OtherPay,
                TotalPay = employeeDto.TotalPay,
                Benefits = employeeDto.Benefits,
                OvertimePay = employeeDto.OvertimePay,
                PensionDebt = employeeDto.PensionDebt ?? decimal.Zero,
                TotalPayWithBenefits = employeeDto.TotalPayWithBenefits,
                EmployeeAgency = OpenReddingEnumConverter.ConvertAgencyFromString(employeeDto.EmployeeAgency),
                EmployeeStatus = OpenReddingEnumConverter.ConvertStatusFromString(employeeDto.EmployeeStatus),
                Notes = employeeDto.Notes,
                Year = employeeDto.Year
            });
        }
        /// <summary>
        /// Maps an employee database model to a view model search DTO.
        /// </summary>
        /// <param name="employee">Employee database model.</param>
        /// <param name="gatewayUrl">Base URL for the API gateway to attach the self link for each record.</param>
        /// <returns>Mapped employee search DTO.</returns>
        /// <exception cref="ArgumentNullException">Throws if entity is null for validation.</exception>
        public static EmployeeSalarySearchResultDto ToEmployeeSalarySearchResultDto(this Employee employee, Uri gatewayUrl)
        {
            ArgumentValidation.CheckNotNull(employee, nameof(employee));

            return(new EmployeeSalarySearchResultDto(
                       employee.EmployeeId,
                       GetEmployeeName(employee),
                       employee.JobTitle,
                       employee.EmployeeAgency.ToFriendlyString(),
                       employee.EmployeeStatus.ToFriendlyString(),
                       employee.Year,
                       employee.BasePay,
                       employee.TotalPayWithBenefits,
                       GetSelfLink(employee.EmployeeId, gatewayUrl)));
        }
        public static RelatedEmployeeDetailDto ToRelatedEmployeeDetailDto(this Employee employee, Uri gatewayUrl)
        {
            ArgumentValidation.CheckNotNull(employee, nameof(employee));

            return(new RelatedEmployeeDetailDto
            {
                Id = employee.EmployeeId,
                Name = GetEmployeeName(employee),
                JobTitle = string.IsNullOrWhiteSpace(employee.JobTitle) ? string.Empty : employee.JobTitle,
                Agency = employee.EmployeeAgency.ToFriendlyString(),
                BasePay = employee.BasePay,
                TotalPayWithBenefits = employee.TotalPayWithBenefits,
                Year = employee.Year,
                Self = GetSelfLink(employee.EmployeeId, gatewayUrl)
            });
        }
        public static EmployeeSalaryExportDto ToSalaryExportDto(this Employee employee)
        {
            ArgumentValidation.CheckNotNull(employee, nameof(employee));

            return(new EmployeeSalaryExportDto(
                       GetEmployeeName(employee),
                       string.IsNullOrWhiteSpace(employee.JobTitle) ? string.Empty : employee.JobTitle,
                       employee.BasePay,
                       employee.OvertimePay,
                       employee.OtherPay,
                       employee.Benefits,
                       employee.TotalPay,
                       employee.PensionDebt ?? 0m,
                       employee.TotalPayWithBenefits,
                       employee.Year,
                       employee.EmployeeAgency,
                       employee.EmployeeStatus));
        }
        /// <summary>
        /// Maps an employee database model to a view model detail DTO.
        /// </summary>
        /// <param name="employee">Employee database model.</param>
        /// <param name="gatewayUrl">Base URL for the API gateway to attach the self link for each record.</param>
        /// <returns>Mapped employee detail DTO.</returns>
        /// <exception cref="ArgumentNullException">Throws if entity is null for validation.</exception>
        public static EmployeeSalaryDetailDto ToEmployeeSalaryDetailDto(this Employee employee, Uri gatewayUrl)
        {
            ArgumentValidation.CheckNotNull(employee, nameof(employee));

            return(new EmployeeSalaryDetailDto
            {
                Id = employee.EmployeeId,
                Name = GetEmployeeName(employee),
                JobTitle = string.IsNullOrWhiteSpace(employee.JobTitle) ? string.Empty : employee.JobTitle,
                BasePay = employee.BasePay,
                Benefits = employee.Benefits,
                OtherPay = employee.OtherPay,
                OvertimePay = employee.OvertimePay,
                TotalPay = employee.TotalPay,
                TotalPayWithBenefits = employee.TotalPayWithBenefits,
                Year = employee.Year,
                Agency = employee.EmployeeAgency.ToString(),
                Status = employee.EmployeeStatus.ToString(),
                Self = GetSelfLink(employee.EmployeeId, gatewayUrl)
            });
        }
        public async Task <OpenReddingLink> CreateBlobWithContents(IEnumerable <object>?results, CancellationToken cancellationToken)
        {
            ArgumentValidation.CheckNotNull(results, nameof(results));

            // Create a temp folder
            _logger.LogInformation("Creating temporary file resources...");
            string tempFolder   = $"{Directory.GetCurrentDirectory()}\\Temp";
            string fileName     = "salaries-" + Guid.NewGuid().ToString() + ".csv";
            string tempFilePath = Path.Combine(tempFolder, fileName);

            _logger.LogInformation($"File to create: {tempFilePath}");

            if (!Directory.Exists(tempFolder))
            {
                _logger.LogInformation($"{tempFolder} directory does not exist, creating...");
                Directory.CreateDirectory(tempFolder);
                _logger.LogInformation($"{tempFolder} directory created successfully!");
            }

            // Write text to the file
            _logger.LogInformation($"Writing file contents to {tempFilePath}");
            using var writer = new StreamWriter(tempFilePath);
            using var csv    = new CsvWriter(writer, CultureInfo.InvariantCulture);
            csv.WriteRecords(results);

            // Dispose of stream resources
            await writer.DisposeAsync();

            await csv.DisposeAsync();

            _logger.LogInformation($"CSV file created successfully, uploading blob to container: {_blobContainerClient.Name}");

            // Get a reference to a blob
            BlobClient blobClient = _blobContainerClient.GetBlobClient(fileName);

            // Open the file and upload its data
            _logger.LogInformation($"Updated file contents to blob location: {blobClient.Uri}");
            using FileStream uploadFileStream = File.OpenRead(tempFilePath);
            await blobClient.UploadAsync(uploadFileStream, true, cancellationToken : cancellationToken);

            uploadFileStream.Close();
            _logger.LogInformation("Blob successfully uploaded, cleaning up temporary resources...");

            // Clean up temporary resources
            File.Delete(tempFilePath);

            foreach (var file in Directory.GetFiles(tempFolder))
            {
                _logger.LogInformation($"Additional files detected in {tempFolder}, removing file {file}...");
                File.Delete(file);
                _logger.LogInformation($"{file} removed successfully!");
            }

            _logger.LogInformation($"Deleting temporary directory {tempFolder}...");
            Directory.Delete(tempFolder);
            _logger.LogInformation($"{tempFolder} successfully removed, returning blob URI: {blobClient.Uri.AbsoluteUri}");

            // Return the link to the blob
            return(new OpenReddingLink
            {
                Href = blobClient.Uri.AbsoluteUri,
                Method = nameof(HttpMethod.Get),
            });
        }