<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using Core.Abstractions.Extensions;
using Core.Abstractions.Types;
using Core.ApplicationServices.Authorization;
using Core.ApplicationServices.Extensions;
using Core.ApplicationServices.GDPR;
using Core.ApplicationServices.Generic.Write;
using Core.ApplicationServices.Model.Contracts.Write;
using Core.ApplicationServices.Model.Shared;
using Core.ApplicationServices.Model.Shared.Write;
using Core.ApplicationServices.OptionTypes;
using Core.ApplicationServices.Organizations;
using Core.ApplicationServices.References;
using Core.ApplicationServices.SystemUsage;
using Core.DomainModel;
using Core.DomainModel.Events;
using Core.DomainModel.ItContract;
using Core.DomainModel.Organization;
using Core.DomainModel.References;
using Core.DomainServices;
using Core.DomainServices.Generic;
using Core.DomainServices.Role;
using Infrastructure.Services.DataAccess;

namespace Core.ApplicationServices.Contract.Write
{
    public class ItContractWriteService : IItContractWriteService
    {
        private readonly IItContractService _contractService;
        private readonly IEntityIdentityResolver _entityIdentityResolver;
        private readonly IOptionResolver _optionResolver;
        private readonly ITransactionManager _transactionManager;
        private readonly IDomainEvents _domainEvents;
        private readonly IDatabaseControl _databaseControl;
        private readonly IGenericRepository<ItContractAgreementElementTypes> _itContractAgreementElementTypesRepository;
        private readonly IAuthorizationContext _authorizationContext;
        private readonly IOrganizationService _organizationService;
        private readonly IGenericRepository<HandoverTrial> _handoverTrialRepository;
        private readonly IReferenceService _referenceService;
        private readonly IAssignmentUpdateService _assignmentUpdateService;
        private readonly IItSystemUsageService _usageService;
        private readonly IRoleAssignmentService<ItContractRight, ItContractRole, ItContract> _roleAssignmentService;
        private readonly IDataProcessingRegistrationApplicationService _dataProcessingRegistrationApplicationService;
        private readonly IGenericRepository<PaymentMilestone> _paymentMilestoneRepository;
        private readonly IGenericRepository<EconomyStream> _economyStreamRepository;

        public ItContractWriteService(
            IItContractService contractService,
            IEntityIdentityResolver entityIdentityResolver,
            IOptionResolver optionResolver,
            ITransactionManager transactionManager,
            IDomainEvents domainEvents,
            IDatabaseControl databaseControl,
            IGenericRepository<ItContractAgreementElementTypes> itContractAgreementElementTypesRepository,
            IAuthorizationContext authorizationContext,
            IOrganizationService organizationService,
            IGenericRepository<HandoverTrial> handoverTrialRepository,
            IReferenceService referenceService,
            IAssignmentUpdateService assignmentUpdateService,
            IItSystemUsageService usageService,
            IRoleAssignmentService<ItContractRight, ItContractRole, ItContract> roleAssignmentService,
            IDataProcessingRegistrationApplicationService dataProcessingRegistrationApplicationService,
            IGenericRepository<PaymentMilestone> paymentMilestoneRepository,
            IGenericRepository<EconomyStream> economyStreamRepository)
        {
            _contractService = contractService;
            _entityIdentityResolver = entityIdentityResolver;
            _optionResolver = optionResolver;
            _transactionManager = transactionManager;
            _domainEvents = domainEvents;
            _databaseControl = databaseControl;
            _itContractAgreementElementTypesRepository = itContractAgreementElementTypesRepository;
            _authorizationContext = authorizationContext;
            _organizationService = organizationService;
            _handoverTrialRepository = handoverTrialRepository;
            _referenceService = referenceService;
            _assignmentUpdateService = assignmentUpdateService;
            _usageService = usageService;
            _roleAssignmentService = roleAssignmentService;
            _dataProcessingRegistrationApplicationService = dataProcessingRegistrationApplicationService;
            _paymentMilestoneRepository = paymentMilestoneRepository;
            _economyStreamRepository = economyStreamRepository;
        }

        public Result<ItContract, OperationError> Create(Guid organizationUuid, ItContractModificationParameters parameters)
        {
            if (parameters == null)
                throw new ArgumentNullException(nameof(parameters));

            if (parameters.Name.IsUnchanged)
                return new OperationError("Name must be provided", OperationFailure.BadInput);

            using var transaction = _transactionManager.Begin();

            var orgId = _entityIdentityResolver.ResolveDbId<Organization>(organizationUuid);
            if (orgId.IsNone)
                return new OperationError("Organization id not valid", OperationFailure.BadInput);

            var nameNewValue = parameters.Name.NewValue;

            parameters.Name = OptionalValueChange<string>.None; //Do not update after creation

            var result = _contractService
                .Create(orgId.Value, nameNewValue)
                .Bind(contract => ApplyUpdates(contract, parameters));

            if (result.Ok)
            {
                _databaseControl.SaveChanges();
                transaction.Commit();
            }

            return result;
        }

        public Result<ItContract, OperationError> Update(Guid itContractUuid, ItContractModificationParameters parameters)
        {
            if (parameters == null)
                throw new ArgumentNullException(nameof(parameters));

            using var transaction = _transactionManager.Begin();

            var updateResult = _contractService
                .GetContract(itContractUuid)
                .Bind(WithWriteAccess)
                .Bind(contract => ApplyUpdates(contract, parameters));

            if (updateResult.Ok)
            {
                _domainEvents.Raise(new EntityUpdatedEvent<ItContract>(updateResult.Value));
                _databaseControl.SaveChanges();
                transaction.Commit();
            }

            return updateResult;
        }

        private Result<ItContract, OperationError> WithWriteAccess(ItContract contract)
        {
            if (!_authorizationContext.AllowModify(contract))
            {
                return new OperationError(OperationFailure.Forbidden);
            }

            return contract;
        }

        private Result<ItContract, OperationError> ApplyUpdates(ItContract contract, ItContractModificationParameters parameters)
        {
            return contract
                .WithOptionalUpdate(parameters.Name, UpdateName)
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.ParentContractUuid, UpdateParentContract))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.General, UpdateGeneralData))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Procurement, UpdateProcurement))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Responsible, UpdateResponsibleData))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Supplier, UpdateSupplierData))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.DataProcessingRegistrationUuids, UpdateDataProcessingRegistrations))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.SystemUsageUuids, UpdateSystemAssignments))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.HandoverTrials, UpdateHandOverTrials))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.PaymentModel, UpdatePaymentModelParameters))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.ExternalReferences, UpdateExternalReferences))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Roles, UpdateRoles))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.AgreementPeriod, UpdateAgreementPeriod))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Payments, UpdatePayments));
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Termination, UpdateTermination));
        }

        private Result<ItContract, OperationError> UpdatePayments(ItContract contract, ItContractPaymentDataModificationParameters parameters)
        {
            return contract
                .WithOptionalUpdate(parameters.ExternalPayments, UpdateExternalPayments)
                .Bind(updatedContract => updatedContract.WithOptionalUpdate(parameters.InternalPayments, UpdateInternalPayments));
        }

        private Maybe<OperationError> UpdateInternalPayments(ItContract contract, IEnumerable<ItContractPayment> newPaymentState)<commit_msg>fix compiler error<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using Core.Abstractions.Extensions;
using Core.Abstractions.Types;
using Core.ApplicationServices.Authorization;
using Core.ApplicationServices.Extensions;
using Core.ApplicationServices.GDPR;
using Core.ApplicationServices.Generic.Write;
using Core.ApplicationServices.Model.Contracts.Write;
using Core.ApplicationServices.Model.Shared;
using Core.ApplicationServices.Model.Shared.Write;
using Core.ApplicationServices.OptionTypes;
using Core.ApplicationServices.Organizations;
using Core.ApplicationServices.References;
using Core.ApplicationServices.SystemUsage;
using Core.DomainModel;
using Core.DomainModel.Events;
using Core.DomainModel.ItContract;
using Core.DomainModel.Organization;
using Core.DomainModel.References;
using Core.DomainServices;
using Core.DomainServices.Generic;
using Core.DomainServices.Role;
using Infrastructure.Services.DataAccess;

namespace Core.ApplicationServices.Contract.Write
{
    public class ItContractWriteService : IItContractWriteService
    {
        private readonly IItContractService _contractService;
        private readonly IEntityIdentityResolver _entityIdentityResolver;
        private readonly IOptionResolver _optionResolver;
        private readonly ITransactionManager _transactionManager;
        private readonly IDomainEvents _domainEvents;
        private readonly IDatabaseControl _databaseControl;
        private readonly IGenericRepository<ItContractAgreementElementTypes> _itContractAgreementElementTypesRepository;
        private readonly IAuthorizationContext _authorizationContext;
        private readonly IOrganizationService _organizationService;
        private readonly IGenericRepository<HandoverTrial> _handoverTrialRepository;
        private readonly IReferenceService _referenceService;
        private readonly IAssignmentUpdateService _assignmentUpdateService;
        private readonly IItSystemUsageService _usageService;
        private readonly IRoleAssignmentService<ItContractRight, ItContractRole, ItContract> _roleAssignmentService;
        private readonly IDataProcessingRegistrationApplicationService _dataProcessingRegistrationApplicationService;
        private readonly IGenericRepository<PaymentMilestone> _paymentMilestoneRepository;
        private readonly IGenericRepository<EconomyStream> _economyStreamRepository;

        public ItContractWriteService(
            IItContractService contractService,
            IEntityIdentityResolver entityIdentityResolver,
            IOptionResolver optionResolver,
            ITransactionManager transactionManager,
            IDomainEvents domainEvents,
            IDatabaseControl databaseControl,
            IGenericRepository<ItContractAgreementElementTypes> itContractAgreementElementTypesRepository,
            IAuthorizationContext authorizationContext,
            IOrganizationService organizationService,
            IGenericRepository<HandoverTrial> handoverTrialRepository,
            IReferenceService referenceService,
            IAssignmentUpdateService assignmentUpdateService,
            IItSystemUsageService usageService,
            IRoleAssignmentService<ItContractRight, ItContractRole, ItContract> roleAssignmentService,
            IDataProcessingRegistrationApplicationService dataProcessingRegistrationApplicationService,
            IGenericRepository<PaymentMilestone> paymentMilestoneRepository,
            IGenericRepository<EconomyStream> economyStreamRepository)
        {
            _contractService = contractService;
            _entityIdentityResolver = entityIdentityResolver;
            _optionResolver = optionResolver;
            _transactionManager = transactionManager;
            _domainEvents = domainEvents;
            _databaseControl = databaseControl;
            _itContractAgreementElementTypesRepository = itContractAgreementElementTypesRepository;
            _authorizationContext = authorizationContext;
            _organizationService = organizationService;
            _handoverTrialRepository = handoverTrialRepository;
            _referenceService = referenceService;
            _assignmentUpdateService = assignmentUpdateService;
            _usageService = usageService;
            _roleAssignmentService = roleAssignmentService;
            _dataProcessingRegistrationApplicationService = dataProcessingRegistrationApplicationService;
            _paymentMilestoneRepository = paymentMilestoneRepository;
            _economyStreamRepository = economyStreamRepository;
        }

        public Result<ItContract, OperationError> Create(Guid organizationUuid, ItContractModificationParameters parameters)
        {
            if (parameters == null)
                throw new ArgumentNullException(nameof(parameters));

            if (parameters.Name.IsUnchanged)
                return new OperationError("Name must be provided", OperationFailure.BadInput);

            using var transaction = _transactionManager.Begin();

            var orgId = _entityIdentityResolver.ResolveDbId<Organization>(organizationUuid);
            if (orgId.IsNone)
                return new OperationError("Organization id not valid", OperationFailure.BadInput);

            var nameNewValue = parameters.Name.NewValue;

            parameters.Name = OptionalValueChange<string>.None; //Do not update after creation

            var result = _contractService
                .Create(orgId.Value, nameNewValue)
                .Bind(contract => ApplyUpdates(contract, parameters));

            if (result.Ok)
            {
                _databaseControl.SaveChanges();
                transaction.Commit();
            }

            return result;
        }

        public Result<ItContract, OperationError> Update(Guid itContractUuid, ItContractModificationParameters parameters)
        {
            if (parameters == null)
                throw new ArgumentNullException(nameof(parameters));

            using var transaction = _transactionManager.Begin();

            var updateResult = _contractService
                .GetContract(itContractUuid)
                .Bind(WithWriteAccess)
                .Bind(contract => ApplyUpdates(contract, parameters));

            if (updateResult.Ok)
            {
                _domainEvents.Raise(new EntityUpdatedEvent<ItContract>(updateResult.Value));
                _databaseControl.SaveChanges();
                transaction.Commit();
            }

            return updateResult;
        }

        private Result<ItContract, OperationError> WithWriteAccess(ItContract contract)
        {
            if (!_authorizationContext.AllowModify(contract))
            {
                return new OperationError(OperationFailure.Forbidden);
            }

            return contract;
        }

        private Result<ItContract, OperationError> ApplyUpdates(ItContract contract, ItContractModificationParameters parameters)
        {
            return contract
                .WithOptionalUpdate(parameters.Name, UpdateName)
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.ParentContractUuid, UpdateParentContract))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.General, UpdateGeneralData))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Procurement, UpdateProcurement))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Responsible, UpdateResponsibleData))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Supplier, UpdateSupplierData))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.DataProcessingRegistrationUuids, UpdateDataProcessingRegistrations))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.SystemUsageUuids, UpdateSystemAssignments))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.HandoverTrials, UpdateHandOverTrials))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.PaymentModel, UpdatePaymentModelParameters))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.ExternalReferences, UpdateExternalReferences))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Roles, UpdateRoles))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.AgreementPeriod, UpdateAgreementPeriod))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Payments, UpdatePayments))
                .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Termination, UpdateTermination));
        }

        private Result<ItContract, OperationError> UpdatePayments(ItContract contract, ItContractPaymentDataModificationParameters parameters)
        {
            return contract
                .WithOptionalUpdate(parameters.ExternalPayments, UpdateExternalPayments)
                .Bind(updatedContract => updatedContract.WithOptionalUpdate(parameters.InternalPayments, UpdateInternalPayments));
        }

        private Maybe<OperationError> UpdateInternalPayments(ItContract contract, IEnumerable<ItContractPayment> newPaymentState)
{'fraction_non_alphanumeric': 0.05740326191237608, 'fraction_numerical': 0.0, 'mean_word_length': 3.44094674556213, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3871978', 'n_tokens_mistral': 4013, 'n_tokens_neox': 3903, 'n_words': 757}