using AutoMapper; using MagicCarpetContracts.DataModels; using MagicCarpetContracts.Exceptions; using MagicCarpetContracts.Mapper; using MagicCarpetContracts.Resources; using MagicCarpetContracts.StoragesContracts; using MagicCarpetDatabase.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Localization; using Npgsql; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MagicCarpetDatabase.Implementations; internal class EmployeeStorageContract(MagicCarpetDbContext dbContext, IStringLocalizer localizer) : IEmployeeStorageContract { private readonly MagicCarpetDbContext _dbContext = dbContext; private readonly IStringLocalizer _localizer = localizer; public List GetList(bool onlyActive = true, string? postId = null, DateTime? fromBirthDate = null, DateTime? toBirthDate = null, DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null) { try { var query = _dbContext.Employees.AsQueryable(); if (onlyActive) { query = query.Where(x => !x.IsDeleted); } if (postId is not null) { query = query.Where(x => x.PostId == postId); } if (fromBirthDate is not null && toBirthDate is not null) { query = query.Where(x => x.BirthDate >= DateTime.SpecifyKind(fromBirthDate ?? DateTime.UtcNow, DateTimeKind.Utc) && x.BirthDate <= DateTime.SpecifyKind(toBirthDate ?? DateTime.UtcNow, DateTimeKind.Utc)); } if (fromEmploymentDate is not null && toEmploymentDate is not null) { query = query.Where(x => x.EmploymentDate >= DateTime.SpecifyKind(fromEmploymentDate ?? DateTime.UtcNow, DateTimeKind.Utc) && x.EmploymentDate <= DateTime.SpecifyKind(toEmploymentDate ?? DateTime.UtcNow, DateTimeKind.Utc)); } return [.. JoinPost(query).Select(x => CustomMapper.MapObject(x))]; } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public EmployeeDataModel? GetElementById(string id) { try { return CustomMapper.MapObjectWithNull(GetEmployeeById(id)); } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public EmployeeDataModel? GetElementByFIO(string fio) { try { return CustomMapper.MapObjectWithNull(AddPost(_dbContext.Employees.FirstOrDefault(x => x.FIO == fio && !x.IsDeleted))); } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public EmployeeDataModel? GetElementByEmail(string email) { try { return CustomMapper.MapObjectWithNull(AddPost(_dbContext.Employees.FirstOrDefault(x => x.Email == email && !x.IsDeleted))); } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public void AddElement(EmployeeDataModel employeeDataModel) { try { _dbContext.Employees.Add(CustomMapper.MapObject(employeeDataModel)); _dbContext.SaveChanges(); } catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict") { _dbContext.ChangeTracker.Clear(); throw new ElementExistsException("Id", employeeDataModel.Id, _localizer); } catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Employees" }) { _dbContext.ChangeTracker.Clear(); throw new ElementExistsException("Id", employeeDataModel.Id, _localizer); } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public void UpdElement(EmployeeDataModel employeeDataModel) { try { var element = GetEmployeeById(employeeDataModel.Id) ?? throw new ElementNotFoundException(employeeDataModel.Id, _localizer); _dbContext.Employees.Update(CustomMapper.MapObject(employeeDataModel, element)); _dbContext.SaveChanges(); } catch (ElementNotFoundException) { _dbContext.ChangeTracker.Clear(); throw; } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public void DelElement(string id) { try { var element = GetEmployeeById(id) ?? throw new ElementNotFoundException(id, _localizer); element.IsDeleted = true; _dbContext.SaveChanges(); } catch (ElementNotFoundException) { _dbContext.ChangeTracker.Clear(); throw; } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } public int GetEmployeeTrend(DateTime fromPeriod, DateTime toPeriod) { try { var countWorkersOnBegining = _dbContext.Employees.Count(x => x.EmploymentDate < fromPeriod && (!x.IsDeleted || x.DateOfDelete > fromPeriod)); var countWorkersOnEnding = _dbContext.Employees.Count(x => x.EmploymentDate < toPeriod && (!x.IsDeleted || x.DateOfDelete > toPeriod)); return countWorkersOnEnding - countWorkersOnBegining; } catch (Exception ex) { _dbContext.ChangeTracker.Clear(); throw new StorageException(ex, _localizer); } } private Employee? GetEmployeeById(string id) => AddPost(_dbContext.Employees.FirstOrDefault(x => x.Id == id && !x.IsDeleted)); private IQueryable JoinPost(IQueryable query) => query.GroupJoin(_dbContext.Posts.Where(x => x.IsActual), x => x.PostId, y => y.PostId, (x, y) => new { Employee = x, Post = y }) .SelectMany(xy => xy.Post.DefaultIfEmpty(), (x, y) => x.Employee.AddPost(y)); private Employee? AddPost(Employee? employee) => employee == null ? null : employee.AddPost(_dbContext.Posts.FirstOrDefault(x => x.PostId == employee.PostId && x.IsActual)); }