using Ease.NetCore.DataAccess;
using Ease.NetCore.DataAccess.SQL;
using Ease.NetCore.Utility;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using OnlineSalesAutoCrop.CoreAPI.Models;
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems;
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;

namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Integrations;

public class IntegrationService : IIntegrationService
{
    private readonly AppSettings _settings;
    private readonly IUserService _userService;

    public IntegrationService(IOptions<AppSettings> options, IUserService userService)
    {
        _settings = options.Value;
        _userService = userService;
    }

    
    public async Task<CustomerByCompanyCodeResponse> GetCustomerByCompanyCodeAsync(CustomerByCompanyCodeRequest request)
    {
        CustomerByCompanyCodeResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                await GetCustomerByCompanyCodeAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationCustomerResponse> UpsertCustomerAsync(IntegrationCustomerRequest request)
    {
        IntegrationCustomerResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode,true);
            try
            {
                var customer = await GetCustomerByCompanyCodeAsync(tc, new CustomerByCompanyCodeRequest() { CompanyCode = request.CompanyCode, CustomerNumber = request.CustomerNumber });

                if( customer != null && customer.CustomerId>0)
                {
                    //Update Here
                    UpdateCustomer(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    //Insert Here 

                    CreateCustomer(tc, request);             
                    response.IsUpdated = false;
                }

                response.CustomerNumber = request.CustomerNumber;
                response.CompanyCode = request.CompanyCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<IntegrationEmployeeResponse> GetEmployeeBySalesOrgAsync(EmployeeIntegrationByComapanyRequest request)
    {
        IntegrationEmployeeResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                await GetEmployeeBySalesOrgAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<EmployeeIntegrationReqResponse> UpsertEmployeeAsync(IntegrationEmployeeRequest request)
    {
        EmployeeIntegrationReqResponse response = new EmployeeIntegrationReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationEmployeeResponse employee = await GetEmployeeBySalesOrgAsync(tc,
                            new EmployeeIntegrationByComapanyRequest() { EmployeeVendorCode = request.EmployeeVendorCode, CompanyCode = request.SalesOrg });


                if (employee != null && employee.EmployeeId > 0)
                {
                    UpdateEmployee(tc, request);             
                    response.IsUpdated = true;
                }
                else
                {
                    InsertEmployee(tc, request);
                    response.IsUpdated = false;
                }

                int roleTypeId = GetRegionAreaTerritoryLevel(request);
                bool isUserExist = await IsUserExistByEmployeeNumberAsync(tc, request.EmployeeVendorCode);

                if (!isUserExist)
                {
                    AppUserCreateRequest appUser = new()
                    {
                        LoginId = request.EmployeeVendorCode,
                        UserName = request.EmployeeVendorCode,
                        Status = (int)EnumStatus.Authorized,
                        AccessStatus = (int)EnumAccessStatus.FirstTime,
                        MobileNo = request.MobileNo,
                        EmailAddress = request.Mail,
                        IsLocked = 0,
                        Password ="12345",
                        UserRoleType = roleTypeId,
                        UserPlatformId = (int)UserPlatFormType.AppUser,
                        EmployeeNumber = request.EmployeeVendorCode
                    };

                    await AddUserAsync(tc, appUser);
                }

                response.EmployeeVendorCode = request.EmployeeVendorCode;
                response.CompanyCode = request.CompanyCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    private  int GetRegionAreaTerritoryLevel(IntegrationEmployeeRequest request)
    {
        bool hasRegion = !string.IsNullOrWhiteSpace(request.RegionAreaCode);
        bool hasArea = !string.IsNullOrWhiteSpace(request.AreaAVSalesUnitCode);
        bool hasTerritory = !string.IsNullOrWhiteSpace(request.Territory);

        if (hasRegion && hasArea && hasTerritory)
        {
            return (int)UserRoleTypeEnum.OrderCollector;
        }

        if (hasRegion && hasArea && !hasTerritory)
        {
            return (int)UserRoleTypeEnum.OrderValidator;
        }

        if (hasRegion && !hasArea && !hasTerritory)
        {
            return (int)UserRoleTypeEnum.OrderApprover;
        }

        return 0;
    }

    public async Task<MaterialIntegrationReqResponse> UpsertMaterialAsync(IntegrationMaterialRequest request)
    {
        MaterialIntegrationReqResponse response = new MaterialIntegrationReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationMaterialResponse meterial = await GetMaterialByCodeAsync(tc,
                            new GetMaterialByCodeRequest() { MaterialCode = request.MaterialCode });

                if (meterial != null && meterial.MeterialId > 0)
                {
                    UpdateMaterial(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    CreateMaterial(tc, request);
                    response.IsUpdated = false;
                }

                response.MaterialCode = request.MaterialCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationMaterialResponse> GetMaterialByCodeAsync(GetMaterialByCodeRequest request)
    {
        IntegrationMaterialResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response= await GetMaterialByCodeAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<MaterialIntegrationPriceReqResponse> UpsertMaterialPriceAsync(IntegrationMaterialPriceRequest request)
    {
        MaterialIntegrationPriceReqResponse response = new MaterialIntegrationPriceReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                var materialPriceType = await GetMaterialPriceTypeAsync(tc, request.ConditionType) ;


                var validationMessages = Validate(request, materialPriceType.PriceType);

                if(validationMessages.Any())
                {
                    throw new Exception(string.Join(", ", validationMessages));
                }

                IntegrationMaterialPriceResponse meterialPrice = null;

                meterialPrice = await GetMaterialPriceByRecordNoAsync(tc, request.ConditionRecNo, materialPriceType.PriceType);

                if (meterialPrice != null && !string.IsNullOrWhiteSpace(meterialPrice.ConditionType))
                {
                    DeleteMaterialPriceByRecordNo(tc, request.ConditionRecNo);
                    CreateMaterialPrice(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    CreateMaterialPrice(tc, request);
                    response.IsUpdated = false;
                }

                response.MaterialCode = request.MaterialCode;
                response.ConditionType = request.ConditionType;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationMaterialPriceResponse> GetMaterialPriceByCodeAsync(GetMaterialPriceByCodeRequest request)
    {
        IntegrationMaterialPriceResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response = await GetMaterialPriceByCodeAndConditionTypeAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<MaterialFreeGoodsByReqResponse> UpsertMaterialFreeGoodsAsync(IntegrationMaterialFreeGoodsRequest request)
    {
        MaterialFreeGoodsByReqResponse response = new MaterialFreeGoodsByReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationMaterialFreeGoodsResponse meterialFreeGoods = await GetMaterialFreeGoodsByRecordNoAsync(tc, request.ConditionRecNo);

                if (meterialFreeGoods != null && meterialFreeGoods.FreeGoodsId >0)
                {
                    DeleteMaterialFreeGoodsByRecordNoAsync(tc, request.ConditionRecNo);
                    CreateMaterialFreeGoods(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    CreateMaterialFreeGoods(tc, request);
                    response.IsUpdated = false;
                }

                response.SalesOrg = request.SalesOrg;
                response.DistributionChannel = request.DistributionChannel;
                response.CustomerPriceGroup = request.CustomerPriceGroup;
                response.MaterialCode = request.MaterialCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationMaterialFreeGoodsResponse> GetMaterialFreeGoodseByFilterAsync(GetMaterialFreeGoodsByFilterRequest request)
    {
        IntegrationMaterialFreeGoodsResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response = await GetMaterialFreeGoodsByFilterAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<IntegrationPaymentTermReqResponse> UpsertPaymentTermsAsync(IntegrationPaymentTermRequest request)
    {
        IntegrationPaymentTermReqResponse response = new IntegrationPaymentTermReqResponse();

        using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
        try
        {
            IntegrationPaymentTermResponse paymentTerms = await GetPaymentTermByFilterAsync(tc,
                        new GetIntegrationPaymentTermRequest()
                        {
                            CreditCode = request.CreditCode,
                            SalesOrg = request.SalesOrg
                        });

            if (paymentTerms != null && !string.IsNullOrWhiteSpace(paymentTerms.CreditCode))
            {
                UpdatePaymentTerm(tc, request);
                response.IsUpdated = true;
            }
            else
            {
                CreatePaymentTerm(tc, request);
                response.IsUpdated = false;
            }

            response.SalesOrg = request.SalesOrg;
            response.CreditCode = request.CreditCode;
            tc.End();
        }
        catch (Exception ie)
        {
            tc?.HandleError();

            throw DBCustomError.GenerateCustomError(ie);
        }

        return response;
    }

    public async Task<IntegrationPaymentTermResponse> GetPaymentTermsByFilterAsync(GetIntegrationPaymentTermRequest request)
    {
        IntegrationPaymentTermResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response = await GetPaymentTermByFilterAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }



    #region Customer Private Functions

    private async Task<CustomerByCompanyCodeResponse> GetCustomerByCompanyCodeAsync(TransactionContext tc, CustomerByCompanyCodeRequest request)
    {
        CustomerByCompanyCodeResponse response = new CustomerByCompanyCodeResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",    pType: SqlDbType.NVarChar, pValue: request.CompanyCode),
                SqlHelperExtension.CreateInParam(pName: "@CustomerNumber", pType: SqlDbType.NVarChar, pValue: request.CustomerNumber)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetCustomerByCompanyCode", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new CustomerByCompanyCodeResponse()
                    {
                        CustomerId = dr.GetInt32(0),
                        CustomerNumber = dr.GetString(1),
                        CustomerName = dr.GetString(2),
                        AccountGroup = dr.GetString(3),
                        AccountGroupDescription = dr.GetString(4),
                        CompanyCode = dr.GetString(5),
                        CompanyCodeDescription = dr.GetString(6),
                        SalesOrganization = dr.GetString(7),
                        SalesOrganizationDescription = dr.GetString(8),
                        DistributionChannel = dr.GetString(9),
                        DistributionChannelDescription = dr.GetString(10),
                        Division = dr.GetString(11),
                        DivisionDescription = dr.GetString(12),
                        MobileNumber = dr.GetString(13),
                        EmailAddress = dr.GetString(14),
                        BusinessTaxNumber =dr.IsDBNull(15)? null: dr.GetString(15),
                        CreditLimit = dr.GetDecimal(16),
                        SalesGroup = dr.IsDBNull(17) ? null: dr.GetString(17),
                        SalesGroupDescription = dr.IsDBNull(18) ? null : dr.GetString(18),
                        CustomerGroup = dr.IsDBNull(19) ? null : dr.GetString(19),
                        CustomerGroupDescription = dr.IsDBNull(20) ? null : dr.GetString(20),
                        CustomerPriceGroup = dr.IsDBNull(21) ? null : dr.GetString(21),
                        CustomerPriceGroupDescription = dr.IsDBNull(22) ? null : dr.GetString(22),
                        StatusCode = dr.IsDBNull(23) ? null : dr.GetString(23),
                        StatusDescription = dr.IsDBNull(24) ? null : dr.GetString(24),
                        PaymentTerms = dr.GetString(25),
                        PaymentTermsDescription = dr.GetString(26),
                        SearchTerm = dr.GetString(27),
                        AreaRegion = dr.GetString(28),
                        AreaRegionDescription = dr.GetString(29),
                        SalesUnitAreaAV = dr.GetString(30),
                        SalesUnitAreaAVDescription = dr.GetString(31),
                        Territory = dr.GetString(32),
                        TerritoryName = dr.GetString(33),
                        Plant = dr.GetString(34),
                        PlantName = dr.GetString(35)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }
    
    private bool CreateCustomer(TransactionContext tc, IntegrationCustomerRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CustomerNumber",                 SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerName",                   SqlDbType.NVarChar, request.CustomerName),

                SqlHelperExtension.CreateInParam("@AccountGroup",                   SqlDbType.NVarChar, request.AccountGroup),
                SqlHelperExtension.CreateInParam("@AccountGroupDescription",        SqlDbType.NVarChar, request.AccountGroupDescription),

                SqlHelperExtension.CreateInParam("@CompanyCode",                    SqlDbType.NVarChar, request.CompanyCode),
                SqlHelperExtension.CreateInParam("@CompanyCodeDescription",         SqlDbType.NVarChar, request.CompanyCodeDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",              SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription",   SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@DistributionChannel",            SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@DistributionChannelDescription", SqlDbType.NVarChar, request.DistributionChannelDescription),

                SqlHelperExtension.CreateInParam("@Division",                       SqlDbType.NVarChar, request.Division),
                SqlHelperExtension.CreateInParam("@DivisionDescription",            SqlDbType.NVarChar, request.DivisionDescription),

                SqlHelperExtension.CreateInParam("@MobileNumber",                   SqlDbType.NVarChar, request.MobileNumber),
                SqlHelperExtension.CreateInParam("@EmailAddress",                   SqlDbType.NVarChar, request.EmailAddress),

                SqlHelperExtension.CreateInParam("@BusinessTaxNumber",              SqlDbType.NVarChar, request.BusinessTaxNumber),
                SqlHelperExtension.CreateInParam("@CreditLimit",                    SqlDbType.Decimal,  request.CreditLimit),

                SqlHelperExtension.CreateInParam("@SalesGroup",                     SqlDbType.NVarChar, request.SalesGroup),
                SqlHelperExtension.CreateInParam("@SalesGroupDescription",          SqlDbType.NVarChar, request.SalesGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerGroup",                  SqlDbType.NVarChar, request.CustomerGroup),
                SqlHelperExtension.CreateInParam("@CustomerGroupDescription",       SqlDbType.NVarChar, request.CustomerGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",             SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroupDescription",  SqlDbType.NVarChar, request.CustomerPriceGroupDescription),

                SqlHelperExtension.CreateInParam("@StatusCode",                     SqlDbType.NChar,    request.StatusCode),
                SqlHelperExtension.CreateInParam("@StatusDescription",              SqlDbType.NVarChar, request.StatusDescription),

                SqlHelperExtension.CreateInParam("@PaymentTerms",                   SqlDbType.NVarChar, request.PaymentTerms),
                SqlHelperExtension.CreateInParam("@PaymentTermsDescription",        SqlDbType.NVarChar, request.PaymentTermsDescription),

                SqlHelperExtension.CreateInParam("@SearchTerm",                     SqlDbType.NVarChar, request.SearchTerm),

                SqlHelperExtension.CreateInParam("@AreaRegion",                     SqlDbType.NVarChar, request.AreaRegion),
                SqlHelperExtension.CreateInParam("@AreaRegionDescription",          SqlDbType.NVarChar, request.AreaRegionDescription),

                SqlHelperExtension.CreateInParam("@SalesUnitAreaAV",                SqlDbType.NVarChar, request.SalesUnitAreaAV),
                SqlHelperExtension.CreateInParam("@SalesUnitAreaAVDescription",     SqlDbType.NVarChar, request.SalesUnitAreaAVDescription),

                SqlHelperExtension.CreateInParam("@Territory",                      SqlDbType.NVarChar, request.Territory),
                SqlHelperExtension.CreateInParam("@TerritoryName",                  SqlDbType.NVarChar, request.TerritoryName),

                SqlHelperExtension.CreateInParam("@Plant",                          SqlDbType.NVarChar, request.Plant),
                SqlHelperExtension.CreateInParam("@PlantName",                      SqlDbType.NVarChar, request.PlantName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.CreateCustomer", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private bool UpdateCustomer(TransactionContext tc, IntegrationCustomerRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CustomerNumber",                 SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerName",                   SqlDbType.NVarChar, request.CustomerName),

                SqlHelperExtension.CreateInParam("@AccountGroup",                   SqlDbType.NVarChar, request.AccountGroup),
                SqlHelperExtension.CreateInParam("@AccountGroupDescription",        SqlDbType.NVarChar, request.AccountGroupDescription),

                SqlHelperExtension.CreateInParam("@CompanyCode",                    SqlDbType.NVarChar, request.CompanyCode),
                SqlHelperExtension.CreateInParam("@CompanyCodeDescription",         SqlDbType.NVarChar, request.CompanyCodeDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",              SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription",   SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@DistributionChannel",            SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@DistributionChannelDescription", SqlDbType.NVarChar, request.DistributionChannelDescription),

                SqlHelperExtension.CreateInParam("@Division",                       SqlDbType.NVarChar, request.Division),
                SqlHelperExtension.CreateInParam("@DivisionDescription",            SqlDbType.NVarChar, request.DivisionDescription),

                SqlHelperExtension.CreateInParam("@MobileNumber",                   SqlDbType.NVarChar, request.MobileNumber),
                SqlHelperExtension.CreateInParam("@EmailAddress",                   SqlDbType.NVarChar, request.EmailAddress),

                SqlHelperExtension.CreateInParam("@BusinessTaxNumber",              SqlDbType.NVarChar, request.BusinessTaxNumber),
                SqlHelperExtension.CreateInParam("@CreditLimit",                    SqlDbType.Decimal,  request.CreditLimit),

                SqlHelperExtension.CreateInParam("@SalesGroup",                     SqlDbType.NVarChar, request.SalesGroup),
                SqlHelperExtension.CreateInParam("@SalesGroupDescription",          SqlDbType.NVarChar, request.SalesGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerGroup",                  SqlDbType.NVarChar, request.CustomerGroup),
                SqlHelperExtension.CreateInParam("@CustomerGroupDescription",       SqlDbType.NVarChar, request.CustomerGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",             SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroupDescription",  SqlDbType.NVarChar, request.CustomerPriceGroupDescription),

                SqlHelperExtension.CreateInParam("@StatusCode",                     SqlDbType.NChar,    request.StatusCode),
                SqlHelperExtension.CreateInParam("@StatusDescription",              SqlDbType.NVarChar, request.StatusDescription),

                SqlHelperExtension.CreateInParam("@PaymentTerms",                   SqlDbType.NVarChar, request.PaymentTerms),
                SqlHelperExtension.CreateInParam("@PaymentTermsDescription",        SqlDbType.NVarChar, request.PaymentTermsDescription),

                SqlHelperExtension.CreateInParam("@SearchTerm",                     SqlDbType.NVarChar, request.SearchTerm),

                SqlHelperExtension.CreateInParam("@AreaRegion",                     SqlDbType.NVarChar, request.AreaRegion),
                SqlHelperExtension.CreateInParam("@AreaRegionDescription",          SqlDbType.NVarChar, request.AreaRegionDescription),

                SqlHelperExtension.CreateInParam("@SalesUnitAreaAV",                SqlDbType.NVarChar, request.SalesUnitAreaAV),
                SqlHelperExtension.CreateInParam("@SalesUnitAreaAVDescription",     SqlDbType.NVarChar, request.SalesUnitAreaAVDescription),

                SqlHelperExtension.CreateInParam("@Territory",                      SqlDbType.NVarChar, request.Territory),
                SqlHelperExtension.CreateInParam("@TerritoryName",                  SqlDbType.NVarChar, request.TerritoryName),

                SqlHelperExtension.CreateInParam("@Plant",                          SqlDbType.NVarChar, request.Plant),
                SqlHelperExtension.CreateInParam("@PlantName",                      SqlDbType.NVarChar, request.PlantName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateCustomer", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Employee Private Functions

    private async Task<IntegrationEmployeeResponse> GetEmployeeBySalesOrgAsync(TransactionContext tc, EmployeeIntegrationByComapanyRequest request)
    {
        IntegrationEmployeeResponse response = new IntegrationEmployeeResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorCode", pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorCode),
                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",        pType: SqlDbType.NVarChar, pValue: request.CompanyCode)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetEmployeeByVendorCode", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new IntegrationEmployeeResponse()
                    {
                        EmployeeId = dr.GetInt32(0),
                        EmployeeVendorCode = dr.GetString(1),
                        EmployeeVendorName = dr.GetString(2),
                        Designation = dr.GetString(3),
                        DesignationDescription = dr.GetString(4),
                        MobileNo = dr.GetString(5),
                        Mail = dr.GetString(6),
                        CompanyCode = dr.GetString(7),
                        CompanyName = dr.GetString(8),
                        SalesOrg = dr.GetString(9),
                        SalesOrgDescription = dr.GetString(10),
                        DistChannel = dr.GetString(11),
                        DistChannelDescription = dr.GetString(12),
                        Division = dr.GetString(13),
                        DivisionDescription = dr.GetString(14),
                        RegionAreaCode = dr.GetString(15),
                        RegionAreaDescription = dr.GetString(16),
                        AreaAVSalesUnitCode = dr.GetString(17),
                        AreaAVSalesUnitDescription = dr.GetString(18),
                        Territory = dr.GetString(19),
                        TerritoryDescription = dr.GetString(20),
                        Plant = dr.GetString(21),
                        PlantDescription = dr.GetString(22),
                        Status = dr.GetString(23),
                        StatusDescription = dr.GetString(24)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }


    public async Task<bool> AddUserAsync(TransactionContext tc, AppUserCreateRequest user)
    {
        bool returnValue;
        try
        {
            int userId = 0;
            user.Password = EncryptPassword(password: user.Password);

            if (!string.IsNullOrEmpty(user.EmailAddress))
                user.EmailAddress = user.EmailAddress.Replace(" ", "");


            SqlParameter[] p =
            [
                    SqlHelperExtension.CreateInParam(pName: "@LoginId",        pType: SqlDbType.VarChar, pValue: user.LoginId,                                size: 100),
                    SqlHelperExtension.CreateInParam(pName: "@UserName",       pType: SqlDbType.VarChar, pValue: user.UserName,                               size: 150),
                    SqlHelperExtension.CreateInParam(pName: "@Status",         pType: SqlDbType.Int,     pValue: user.Status),
                    SqlHelperExtension.CreateInParam(pName: "@AccessStatus",   pType: SqlDbType.Int,     pValue: user.AccessStatus),
                    SqlHelperExtension.CreateInParam(pName: "@MobileNo",       pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(user.MobileNo),       size: 20),
                    SqlHelperExtension.CreateInParam(pName: "@EmailAddress",   pType: SqlDbType.VarChar, pValue: user.EmailAddress,                           size: 200),
                    SqlHelperExtension.CreateInParam(pName: "@IsLocked",       pType: SqlDbType.Int,     pValue: user.IsLocked),
                    SqlHelperExtension.CreateInParam(pName: "@Password",       pType: SqlDbType.NVarChar, pValue: user.Password,                               size: 500),
                    SqlHelperExtension.CreateInParam(pName: "@UserPlatformId", pType: SqlDbType.Int,     pValue: DataReader.GetNullValue(user.UserPlatformId)),
                    SqlHelperExtension.CreateInParam(pName: "@UserRoleType",   pType: SqlDbType.Int,     pValue: DataReader.GetNullValue(user.UserRoleType)),
                    SqlHelperExtension.CreateInParam(pName: "@EmployeeNumber", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(user.EmployeeNumber), size: 10),
                    SqlHelperExtension.CreateOutParam(pName: "@NewUserId",     pType: SqlDbType.Int)      // index 11 — output
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertUser", parameterValues: p);
            userId = (p[11]?.Value != null && p[11]?.Value != DBNull.Value)
                ? Convert.ToInt32(p[11].Value)
                : 0;

            returnValue = userId > 0;
        }
        catch (Exception e)
        {
            throw new InvalidOperationException(e.Message, e);
        }

        return returnValue;
    }


    private string EncryptPassword(string password)
    {
        try
        {
            string pwdSecretKey = GlobalFunctions.ConvertFromBase64String(_settings.PwdSecretKey);
            return Global.CipherFunctions.EncryptByAES(privateKey: pwdSecretKey, publicKey: pwdSecretKey, data: password);
        }
        catch (Exception e)
        {
            throw new InvalidOperationException(e.Message, e);
        }

    }

    private async Task<bool> IsUserExistByEmployeeNumberAsync(TransactionContext tc, string employeeNumber)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeNumber", pType: SqlDbType.NVarChar, pValue: employeeNumber)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.IsUserExistByEmployeeNumber", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = dr.GetInt32(0) > 0 ? true: false;                 
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool InsertEmployee(TransactionContext tc, IntegrationEmployeeRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorCode",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorCode),
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorName",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorName),

                SqlHelperExtension.CreateInParam(pName: "@Designation",                pType: SqlDbType.NVarChar, pValue: request.Designation),
                SqlHelperExtension.CreateInParam(pName: "@DesignationDescription",     pType: SqlDbType.NVarChar, pValue: request.DesignationDescription),

                SqlHelperExtension.CreateInParam(pName: "@MobileNo",                   pType: SqlDbType.NVarChar, pValue: request.MobileNo),
                SqlHelperExtension.CreateInParam(pName: "@Mail",                       pType: SqlDbType.NVarChar, pValue: request.Mail),

                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",                pType: SqlDbType.NVarChar, pValue: request.CompanyCode),
                SqlHelperExtension.CreateInParam(pName: "@CompanyName",                pType: SqlDbType.NVarChar, pValue: request.CompanyName),

                SqlHelperExtension.CreateInParam(pName: "@SalesOrg",                   pType: SqlDbType.NVarChar, pValue: request.SalesOrg),
                SqlHelperExtension.CreateInParam(pName: "@SalesOrgDescription",        pType: SqlDbType.NVarChar, pValue: request.SalesOrgDescription),

                SqlHelperExtension.CreateInParam(pName: "@DistChannel",                pType: SqlDbType.NVarChar, pValue: request.DistChannel),
                SqlHelperExtension.CreateInParam(pName: "@DistChannelDescription",     pType: SqlDbType.NVarChar, pValue: request.DistChannelDescription),

                SqlHelperExtension.CreateInParam(pName: "@Division",                   pType: SqlDbType.NVarChar, pValue: request.Division),
                SqlHelperExtension.CreateInParam(pName: "@DivisionDescription",        pType: SqlDbType.NVarChar, pValue: request.DivisionDescription),

                SqlHelperExtension.CreateInParam(pName: "@RegionAreaCode",             pType: SqlDbType.NVarChar, pValue: request.RegionAreaCode),
                SqlHelperExtension.CreateInParam(pName: "@RegionAreaDescription",      pType: SqlDbType.NVarChar, pValue: request.RegionAreaDescription),

                SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitCode",        pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitCode),
                SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitDescription", pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitDescription),

                SqlHelperExtension.CreateInParam(pName: "@Territory",                  pType: SqlDbType.NVarChar, pValue: request.Territory),
                SqlHelperExtension.CreateInParam(pName: "@TerritoryDescription",       pType: SqlDbType.NVarChar, pValue: request.TerritoryDescription),

                SqlHelperExtension.CreateInParam(pName: "@Plant",                      pType: SqlDbType.NVarChar, pValue: request.Plant),
                SqlHelperExtension.CreateInParam(pName: "@PlantDescription",           pType: SqlDbType.NVarChar, pValue: request.PlantDescription),

                SqlHelperExtension.CreateInParam(pName: "@Status",                     pType: SqlDbType.NChar,    pValue: request.Status),
                SqlHelperExtension.CreateInParam(pName: "@StatusDescription",          pType: SqlDbType.NVarChar, pValue: request.StatusDescription)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertEmployee", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private bool UpdateEmployee(TransactionContext tc, IntegrationEmployeeRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorCode",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorCode),
                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",                pType: SqlDbType.NVarChar, pValue: request.CompanyCode),

                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorName",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorName),

                SqlHelperExtension.CreateInParam(pName: "@Designation",                pType: SqlDbType.NVarChar, pValue: request.Designation),
                SqlHelperExtension.CreateInParam(pName: "@DesignationDescription",     pType: SqlDbType.NVarChar, pValue: request.DesignationDescription),

                SqlHelperExtension.CreateInParam(pName: "@MobileNo",                   pType: SqlDbType.NVarChar, pValue: request.MobileNo),
                SqlHelperExtension.CreateInParam(pName: "@Mail",                       pType: SqlDbType.NVarChar, pValue: request.Mail),

                SqlHelperExtension.CreateInParam(pName: "@CompanyName",                pType: SqlDbType.NVarChar, pValue: request.CompanyName),

                SqlHelperExtension.CreateInParam(pName: "@SalesOrg",                   pType: SqlDbType.NVarChar, pValue: request.SalesOrg),
                SqlHelperExtension.CreateInParam(pName: "@SalesOrgDescription",        pType: SqlDbType.NVarChar, pValue: request.SalesOrgDescription),

                SqlHelperExtension.CreateInParam(pName: "@DistChannel",                pType: SqlDbType.NVarChar, pValue: request.DistChannel),
                SqlHelperExtension.CreateInParam(pName: "@DistChannelDescription",     pType: SqlDbType.NVarChar, pValue: request.DistChannelDescription),

                SqlHelperExtension.CreateInParam(pName: "@Division",                   pType: SqlDbType.NVarChar, pValue: request.Division),
                SqlHelperExtension.CreateInParam(pName: "@DivisionDescription",        pType: SqlDbType.NVarChar, pValue: request.DivisionDescription),

                SqlHelperExtension.CreateInParam(pName: "@RegionAreaCode",             pType: SqlDbType.NVarChar, pValue: request.RegionAreaCode),
                SqlHelperExtension.CreateInParam(pName: "@RegionAreaDescription",      pType: SqlDbType.NVarChar, pValue: request.RegionAreaDescription),

                SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitCode",        pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitCode),
                SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitDescription", pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitDescription),

                SqlHelperExtension.CreateInParam(pName: "@Territory",                  pType: SqlDbType.NVarChar, pValue: request.Territory),
                SqlHelperExtension.CreateInParam(pName: "@TerritoryDescription",       pType: SqlDbType.NVarChar, pValue: request.TerritoryDescription),

                SqlHelperExtension.CreateInParam(pName: "@Plant",                      pType: SqlDbType.NVarChar, pValue: request.Plant),
                SqlHelperExtension.CreateInParam(pName: "@PlantDescription",           pType: SqlDbType.NVarChar, pValue: request.PlantDescription),

                SqlHelperExtension.CreateInParam(pName: "@Status",                     pType: SqlDbType.NChar,    pValue: request.Status),
                SqlHelperExtension.CreateInParam(pName: "@StatusDescription",          pType: SqlDbType.NVarChar, pValue: request.StatusDescription)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateEmployee", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Meterial Private Functions

    private async Task<IntegrationMaterialResponse> GetMaterialByCodeAsync(TransactionContext tc, GetMaterialByCodeRequest request)
    {
        IntegrationMaterialResponse response = new IntegrationMaterialResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@MaterialCode", pType: SqlDbType.NVarChar, pValue: request.MaterialCode)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetMaterialByMaterialCode", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new IntegrationMaterialResponse()
                    {
                        MeterialId = dr.GetInt32(0),
                        MaterialType = dr.GetString(1),
                        MaterialTypeDescription = dr.GetString(2),
                        MaterialCode = dr.GetString(3),
                        MaterialDescription = dr.GetString(4),
                        MaterialGroupCode = dr.GetString(5),
                        MaterialGroupDescription = dr.GetString(6),
                        BaseUnitOfMeasure = dr.GetString(7),
                        SalesUnitOfMeasure = dr.GetString(8),
                        UnitConversionWithBaseUoM = dr.GetDecimal(9),
                        PlantCode = dr.GetString(10),
                        PlantDescription = dr.GetString(11),
                        StorageLocationCode = dr.GetString(12),
                        StorageLocationDescription = dr.GetString(13),
                        SalesOrganization = dr.GetString(14),
                        SalesOrganizationDescription = dr.GetString(15),
                        BrandCode = dr.GetString(16),
                        BrandName = dr.GetString(17)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreateMaterial(TransactionContext tc, IntegrationMaterialRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@MaterialType",               SqlDbType.NVarChar, request.MaterialType),
                SqlHelperExtension.CreateInParam("@MaterialTypeDescription",     SqlDbType.NVarChar, request.MaterialTypeDescription),

                SqlHelperExtension.CreateInParam("@MaterialCode",               SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@MaterialDescription",        SqlDbType.NVarChar, request.MaterialDescription),

                SqlHelperExtension.CreateInParam("@MaterialGroupCode",          SqlDbType.NVarChar, request.MaterialGroupCode),
                SqlHelperExtension.CreateInParam("@MaterialGroupDescription",   SqlDbType.NVarChar, request.MaterialGroupDescription),

                SqlHelperExtension.CreateInParam("@BaseUnitOfMeasure",          SqlDbType.NVarChar, request.BaseUnitOfMeasure),
                SqlHelperExtension.CreateInParam("@SalesUnitOfMeasure",         SqlDbType.NVarChar, request.SalesUnitOfMeasure),

                SqlHelperExtension.CreateInParam("@UnitConversionWithBaseUoM",  SqlDbType.Decimal,  request.UnitConversionWithBaseUoM),

                SqlHelperExtension.CreateInParam("@PlantCode",                  SqlDbType.NVarChar, request.PlantCode),
                SqlHelperExtension.CreateInParam("@PlantDescription",           SqlDbType.NVarChar, request.PlantDescription),

                SqlHelperExtension.CreateInParam("@StorageLocationCode",        SqlDbType.NVarChar, request.StorageLocationCode),
                SqlHelperExtension.CreateInParam("@StorageLocationDescription", SqlDbType.NVarChar, request.StorageLocationDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",            SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@BrandCode",                    SqlDbType.NVarChar, request.BrandCode),
                SqlHelperExtension.CreateInParam("@BrandName",                    SqlDbType.NVarChar, request.BrandName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.CreateMaterial", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private bool UpdateMaterial(TransactionContext tc, IntegrationMaterialRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@MaterialType",               SqlDbType.NVarChar, request.MaterialType),
                SqlHelperExtension.CreateInParam("@MaterialTypeDescription",     SqlDbType.NVarChar, request.MaterialTypeDescription),

                SqlHelperExtension.CreateInParam("@MaterialCode",               SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@MaterialDescription",        SqlDbType.NVarChar, request.MaterialDescription),

                SqlHelperExtension.CreateInParam("@MaterialGroupCode",          SqlDbType.NVarChar, request.MaterialGroupCode),
                SqlHelperExtension.CreateInParam("@MaterialGroupDescription",   SqlDbType.NVarChar, request.MaterialGroupDescription),

                SqlHelperExtension.CreateInParam("@BaseUnitOfMeasure",          SqlDbType.NVarChar, request.BaseUnitOfMeasure),
                SqlHelperExtension.CreateInParam("@SalesUnitOfMeasure",         SqlDbType.NVarChar, request.SalesUnitOfMeasure),

                SqlHelperExtension.CreateInParam("@UnitConversionWithBaseUoM",  SqlDbType.Decimal,  request.UnitConversionWithBaseUoM),

                SqlHelperExtension.CreateInParam("@PlantCode",                  SqlDbType.NVarChar, request.PlantCode),
                SqlHelperExtension.CreateInParam("@PlantDescription",           SqlDbType.NVarChar, request.PlantDescription),

                SqlHelperExtension.CreateInParam("@StorageLocationCode",        SqlDbType.NVarChar, request.StorageLocationCode),
                SqlHelperExtension.CreateInParam("@StorageLocationDescription", SqlDbType.NVarChar, request.StorageLocationDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",            SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@BrandCode",                    SqlDbType.NVarChar, request.BrandCode),
                SqlHelperExtension.CreateInParam("@BrandName",                    SqlDbType.NVarChar, request.BrandName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateMaterial", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Material Price Private Functions

    private async Task<IntegrationMaterialPriceResponse> GetMaterialPriceByCodeAndConditionTypeAsync(
        TransactionContext tc, GetMaterialPriceByCodeRequest request)
    {
        IntegrationMaterialPriceResponse response = new IntegrationMaterialPriceResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",  SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@MaterialCode",  SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ConditionType", SqlDbType.NVarChar, request.ConditionType),
                SqlHelperExtension.CreateInParam("@CustomerNumber", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerNumber)? null : request.CustomerNumber ),
                SqlHelperExtension.CreateInParam("@CustomerGroup", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerGroupCode)? null : request.CustomerGroupCode ),
                SqlHelperExtension.CreateInParam("@DistributorChannelCode", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.DistributorChannelCode)? null : request.DistributorChannelCode ),
                SqlHelperExtension.CreateInParam("@FromValid", SqlDbType.DateTime,  request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ToValid", SqlDbType.DateTime,  request.ValidTo)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetMaterialPriceByMaterialCodeAndConditionType", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new IntegrationMaterialPriceResponse()
                    {
                        MaterialPriceId = dr.GetInt32(0),
                        SalesOrg = dr.IsDBNull(1) ? null : dr.GetString(1),
                        DistributionChannel = dr.IsDBNull(2) ? null : dr.GetString(2),
                        CustomerNumber = dr.IsDBNull(3) ? null : dr.GetString(3),
                        CustomerGroupCode = dr.IsDBNull(4) ? null : dr.GetString(4),
                        MaterialCode = dr.GetString(5),
                        ConditionType = dr.GetString(6),
                        CalculationType = dr.GetString(7),
                        PricingUnit = dr.GetString(8),
                        UnitOfMeasure = dr.GetString(9),
                        ValidFrom = dr.GetDateTime(10),
                        ValidTo = dr.GetDateTime(11),
                        Status = dr.IsDBNull(12) ? null : dr.GetString(12),
                        ConditionValue = dr.GetDecimal(13)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private async Task<IntegrationMaterialPriceResponse> GetMaterialPriceByRecordNoAsync(
        TransactionContext tc, int? conditionRecordNo, MaterialPriceTypeEnum priceType )
    {
        IntegrationMaterialPriceResponse response = new IntegrationMaterialPriceResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@ConditionRecNo",  SqlDbType.Int, conditionRecordNo),
                SqlHelperExtension.CreateInParam("@PriceType",  SqlDbType.Int,(int) priceType),
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetMaterialPriceByConditionRecordNo", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new IntegrationMaterialPriceResponse()
                    {
                        MaterialPriceId = dr.GetInt32(0),
                        SalesOrg = dr.IsDBNull(1) ? null : dr.GetString(1),
                        DistributionChannel = dr.IsDBNull(2) ? null : dr.GetString(2),
                        CustomerNumber = dr.IsDBNull(3) ? null : dr.GetString(3),
                        CustomerGroupCode = dr.IsDBNull(4) ? null : dr.GetString(4),
                        MaterialCode = dr.IsDBNull(5) ? null : dr.GetString(5),
                        ConditionType = dr.GetString(6),
                        CalculationType = dr.GetString(7),
                        PricingUnit = dr.IsDBNull(8) ? null : dr.GetString(8),
                        UnitOfMeasure = dr.IsDBNull(9) ? null : dr.GetString(9),
                        ValidFrom = dr.GetDateTime(10),
                        ValidTo = dr.GetDateTime(11),
                        Status = dr.IsDBNull(12) ? null : dr.GetString(12),
                        ConditionValue = dr.GetDecimal(13)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool DeleteMaterialPriceByCodeAndConditionType(TransactionContext tc, GetMaterialPriceByCodeRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",  SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@MaterialCode",  SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ConditionType", SqlDbType.NVarChar, request.ConditionType),
                SqlHelperExtension.CreateInParam("@CustomerNumber", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerNumber)? null : request.CustomerNumber ),
                SqlHelperExtension.CreateInParam("@CustomerGroup", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerGroupCode)? null : request.CustomerGroupCode ),
                SqlHelperExtension.CreateInParam("@DistributorChannelCode", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.DistributorChannelCode)? null : request.DistributorChannelCode )
            ];

            _ = tc.ExecuteNonQuerySp("dbo.DeleteMaterialPriceByMaterialCodeAndConditionType", parameterValues: p);
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool DeleteMaterialPriceByRecordNo(TransactionContext tc, int recordNo)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@ConditionRecNo",  SqlDbType.Int, recordNo),      
            ];

            _ = tc.ExecuteNonQuerySp("dbo.DeleteMaterialPriceByRecordNo", parameterValues: p);
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool InactiveMaterialPriceByCodeAndConditionType(TransactionContext tc, GetMaterialPriceByCodeRequest request, MaterialPriceTypeEnum priceType)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",  SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@MaterialCode",  SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ConditionType", SqlDbType.NVarChar, request.ConditionType),
                SqlHelperExtension.CreateInParam("@CustomerNumber", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerNumber)? null : request.CustomerNumber ),
                SqlHelperExtension.CreateInParam("@CustomerGroup", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerGroupCode)? null : request.CustomerGroupCode ),
                SqlHelperExtension.CreateInParam("@DistributorChannelCode", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.DistributorChannelCode)? null : request.DistributorChannelCode ),
                SqlHelperExtension.CreateInParam("@PriceType", SqlDbType.Int, (int) priceType)
            ];

            _ = tc.ExecuteNonQuerySp("dbo.InActiveMaterialPriceByMaterialCodeAndConditionType", parameterValues: p);
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreateMaterialPrice(TransactionContext tc, IntegrationMaterialPriceRequest request)
    {
        bool response = false;

        try
        {
            if(request.Slabs!= null && request.Slabs.Count > 0)
            {
                foreach (var item in request.Slabs)
                {
                    SqlParameter[] p =
                    [
                        SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                        SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                        SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                        SqlHelperExtension.CreateInParam("@CustomerGroupCode",   SqlDbType.NVarChar, request.CustomerGroupCode),
                        SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                        SqlHelperExtension.CreateInParam("@ConditionType",       SqlDbType.NVarChar, request.ConditionType),
                        SqlHelperExtension.CreateInParam("@CalculationType",     SqlDbType.NVarChar, request.CalculationType),
                        SqlHelperExtension.CreateInParam("@PricingUnit",         SqlDbType.NVarChar, request.PricingUnit),
                        SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                        SqlHelperExtension.CreateInParam("@ScaleValue",          SqlDbType.NVarChar, item.ScaleValue),
                        SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.DateTime, item.ValidFrom),
                        SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.DateTime, item.ValidTo),
                        SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, item.Status),
                        SqlHelperExtension.CreateInParam("@ConditionValue",      SqlDbType.Decimal,  item.ConditionValue)  ,
                        SqlHelperExtension.CreateInParam("@ConditionRecNo",      SqlDbType.Int,      request.ConditionRecNo)  ,
                    ];

                    _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialPrice", parameterValues: p);
                }
            }
            else
            {
                    SqlParameter[] p =
                    [
                        SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                        SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                        SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                        SqlHelperExtension.CreateInParam("@CustomerGroupCode",   SqlDbType.NVarChar, request.CustomerGroupCode),
                        SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                        SqlHelperExtension.CreateInParam("@ConditionType",       SqlDbType.NVarChar, request.ConditionType),
                        SqlHelperExtension.CreateInParam("@CalculationType",     SqlDbType.NVarChar, request.CalculationType),
                        SqlHelperExtension.CreateInParam("@PricingUnit",         SqlDbType.NVarChar, request.PricingUnit),
                        SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                        SqlHelperExtension.CreateInParam("@ScaleValue",          SqlDbType.NVarChar, Convert.ToDecimal(request.PricingUnit ?? "0")),
                        SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.DateTime, request.ValidFrom),
                        SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.DateTime, request.ValidTo),
                        SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, request.Status),
                        SqlHelperExtension.CreateInParam("@ConditionValue",      SqlDbType.Decimal,  request.ConditionValue)  ,
                        SqlHelperExtension.CreateInParam("@ConditionRecNo",      SqlDbType.Int,      request.ConditionRecNo)  ,
                    ];

                _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialPrice", parameterValues: p);
            }

            
            response = true;
        }
        catch (Exception)
        {
            throw;
        }

        return response;
    }

    private bool UpdateMaterialPrice(TransactionContext tc, IntegrationMaterialPriceRequest request)
    {
        bool returnValue = false;

        try
        {
            foreach (var item in request.Slabs)
            {
                SqlParameter[] p =
                [
                    SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                    SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                    SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                    SqlHelperExtension.CreateInParam("@CustomerGroupCode",   SqlDbType.NVarChar, request.CustomerGroupCode),
                    SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                    SqlHelperExtension.CreateInParam("@ConditionType",       SqlDbType.NVarChar, request.ConditionType),
                    SqlHelperExtension.CreateInParam("@CalculationType",     SqlDbType.NVarChar, request.CalculationType),
                    SqlHelperExtension.CreateInParam("@PricingUnit",         SqlDbType.NVarChar, request.PricingUnit),
                    SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                    SqlHelperExtension.CreateInParam("@ScaleValue",          SqlDbType.NVarChar, item.ScaleValue),
                    SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.DateTime, item.ValidFrom),
                    SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.DateTime, item.ValidTo),
                    SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, item.Status),
                    SqlHelperExtension.CreateInParam("@ConditionValue",      SqlDbType.Decimal,  item.ConditionValue),
                    SqlHelperExtension.CreateInParam("@ConditionRecordNo",   SqlDbType.Int,   request.ConditionRecNo)  
                ];

                _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateIntegrationMaterialPrice", parameterValues: p);
            }

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private async Task<MaterialPriceTypeResponse> GetMaterialPriceTypeAsync(TransactionContext tc, string conditionType)
    {
        MaterialPriceTypeResponse response = new MaterialPriceTypeResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@ConditionType", SqlDbType.NVarChar, conditionType)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetMaterialPriceTypeByConditionType", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new MaterialPriceTypeResponse()
                    {
                        PriceTypeId = dr.GetInt32(0),
                        Code = dr.GetString(1),
                        Name = dr.GetString(2),
                        PriceType =(MaterialPriceTypeEnum)dr.GetInt32(3)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }
    #endregion

    #region Material Free Goods Private Functions

    private async Task<IntegrationMaterialFreeGoodsResponse> GetMaterialFreeGoodsByFilterAsync(
        TransactionContext tc, GetMaterialFreeGoodsByFilterRequest request)
    {
        IntegrationMaterialFreeGoodsResponse response = new IntegrationMaterialFreeGoodsResponse();

        try
        {
            SqlParameter[] p =
            [
                
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.NVarChar, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.NVarChar, request.ValidTo),
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetAllMaterialFreeGoodsForUpdate", parameterValues: p))
            {
                while (dr.Read())
                {
                    response= new IntegrationMaterialFreeGoodsResponse()
                    {
                        FreeGoodsId = dr.GetInt32(0),
                        SalesOrg = dr.GetString(1),
                        DistributionChannel = dr.GetString(2),
                        CustomerNumber = dr.IsDBNull(3) ? null : dr.GetString(3),
                        CustomerPriceGroup = dr.GetString(4),
                        MaterialCode = dr.GetString(5),
                        MinOrderQuantity = dr.GetDecimal(6),
                        ForQuantity = dr.GetDecimal(7),
                        UnitOfMeasure = dr.GetString(8),
                        FreeQuantity = dr.GetDecimal(9),
                        FocUnitOfMeasure = dr.GetString(10),
                        ValidFrom =  dr.GetDateTime(11),
                        ValidTo = dr.GetDateTime(12),
                        Status = dr.IsDBNull(13) ? null : dr.GetString(13)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private async Task<IntegrationMaterialFreeGoodsResponse> GetMaterialFreeGoodsByRecordNoAsync(
        TransactionContext tc, int recordNo)
    {
        IntegrationMaterialFreeGoodsResponse response = new IntegrationMaterialFreeGoodsResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@ConditionRecordNo", SqlDbType.NVarChar, recordNo),
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetAllMaterialFreeGoodsByRecordNo", parameterValues: p))
            {
                while (dr.Read())
                {
                    response = new IntegrationMaterialFreeGoodsResponse()
                    {
                        FreeGoodsId = dr.GetInt32(0),
                        SalesOrg = dr.GetString(1),
                        DistributionChannel = dr.GetString(2),
                        CustomerNumber = dr.IsDBNull(3) ? null : dr.GetString(3),
                        CustomerPriceGroup = dr.IsDBNull(4) ? null : dr.GetString(4),
                        MaterialCode = dr.IsDBNull(5) ? null : dr.GetString(5),
                        MinOrderQuantity = dr.IsDBNull(6) ? null : dr.GetDecimal(6),
                        ForQuantity = dr.IsDBNull(7) ? null : dr.GetDecimal(7),
                        UnitOfMeasure = dr.IsDBNull(8) ? null : dr.GetString(8),
                        FreeQuantity = dr.IsDBNull(9) ? null : dr.GetDecimal(9),
                        FocUnitOfMeasure = dr.IsDBNull(10) ? null : dr.GetString(10),
                        ValidFrom = dr.IsDBNull(11) ? null : dr.GetDateTime(11),
                        ValidTo = dr.IsDBNull(12) ? null : dr.GetDateTime(12),
                        Status = dr.IsDBNull(13) ? null : dr.GetString(13)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }


    private bool DeleteMaterialFreeGoodsByFilter(
        TransactionContext tc, GetMaterialFreeGoodsByFilterRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode)
            ];
            _ = tc.ExecuteNonQuerySp("dbo.DeleteMaterialFOCByFilter", parameterValues: p);
            response = true;
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool DeleteMaterialFreeGoodsByRecordNoAsync(
       TransactionContext tc, int conditionRecNo)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@ConditionRecNo",            SqlDbType.Int, conditionRecNo)
            ];
            _ = tc.ExecuteNonQuerySp("dbo.DeleteMaterialFOCByRecordNo", parameterValues: p);
            response = true;
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool InActiveMaterialFreeGoodsByFilter(
        TransactionContext tc, GetMaterialFreeGoodsByFilterRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode)
            ];
            _ = tc.ExecuteNonQuerySp("dbo.InActiveMaterialFOCByFilter", parameterValues: p);
            response = true;
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreateMaterialFreeGoods(TransactionContext tc, IntegrationMaterialFreeGoodsRequest request)
    {
        bool response = false;

        try
        {
            foreach (var item in request.Slabs)
            {
                SqlParameter[] p =
                 [
                    SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                    SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                    SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                    SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                    SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                    SqlHelperExtension.CreateInParam("@MinOrderQuantity",    SqlDbType.Decimal,  item.MinOrderQuantity),
                    SqlHelperExtension.CreateInParam("@ForQuantity",         SqlDbType.Decimal,  item.ForQuantity),
                    SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, item.UnitOfMeasure),
                    SqlHelperExtension.CreateInParam("@FreeQuantity",        SqlDbType.Decimal,  item.FreeQuantity),
                    SqlHelperExtension.CreateInParam("@FocUnitOfMeasure",    SqlDbType.NVarChar, item.FocUnitOfMeasure),
                    SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.Date,     item.ValidFrom),
                    SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.Date,     item.ValidTo),
                    SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, item.Status),
                    SqlHelperExtension.CreateInParam("@ConditionRecNo",      SqlDbType.Int,      request.ConditionRecNo),
                ];

                _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialFreeGoods", parameterValues: p);
            }


            response = true;
        }
        catch (Exception)
        {
            throw;
        }

        return response;
    }

    private bool UpdateMaterialFreeGoods(TransactionContext tc, IntegrationMaterialFreeGoodsRequest request)
    {
        bool returnValue = false;

        try
        {
            foreach (var item in request.Slabs)
            {
                SqlParameter[]  p =
                [
                    SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                    SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                    SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                    SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                    SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                    SqlHelperExtension.CreateInParam("@MinOrderQuantity",    SqlDbType.Decimal,  item.MinOrderQuantity),
                    SqlHelperExtension.CreateInParam("@ForQuantity",         SqlDbType.Decimal,  item.ForQuantity),
                    SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, item.UnitOfMeasure),
                    SqlHelperExtension.CreateInParam("@FreeQuantity",        SqlDbType.Decimal,  item.FreeQuantity),
                    SqlHelperExtension.CreateInParam("@FocUnitOfMeasure",    SqlDbType.NVarChar, item.FocUnitOfMeasure),
                    SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.Date,     item.ValidFrom),
                    SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.Date,     item.ValidTo),
                    SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, item.Status ),
                ];

                _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateIntegrationMaterialFreeGoods", parameterValues: p);
            }

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Payment Terms Private Functions

    private async Task<IntegrationPaymentTermResponse> GetPaymentTermByFilterAsync(TransactionContext tc,
        GetIntegrationPaymentTermRequest request)
    {
        IntegrationPaymentTermResponse response = new IntegrationPaymentTermResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CreditCode", SqlDbType.NVarChar, request.CreditCode),
                SqlHelperExtension.CreateInParam("@SalesOrg",   SqlDbType.NVarChar, request.SalesOrg)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetPaymentTermByFilter", parameterValues: p))
            {
                if (dr.Read())
                {
                    response=new IntegrationPaymentTermResponse()
                    {
                        CreditCodeId = dr.GetInt32(0),
                        CreditCode = dr.GetString(1),
                        Description = dr.GetString(2),
                        ValidFrom = dr.GetDateTime(3),
                        ValidTo = dr.GetDateTime(4),
                        SalesOrg = dr.GetString(5)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreatePaymentTerm(TransactionContext tc, IntegrationPaymentTermRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CreditCode",   SqlDbType.NVarChar, request.CreditCode),
                SqlHelperExtension.CreateInParam("@Description",  SqlDbType.NVarChar, request.Description),
                SqlHelperExtension.CreateInParam("@ValidFrom",    SqlDbType.DateTime, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",      SqlDbType.DateTime, request.ValidTo),
                SqlHelperExtension.CreateInParam("@SalesOrg",     SqlDbType.NVarChar, request.SalesOrg)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationPaymentTerm", parameterValues: p);

            response = true;
        }
        catch (Exception)
        {
            throw;
        }

        return response;
    }

    private bool UpdatePaymentTerm(TransactionContext tc, IntegrationPaymentTermRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CreditCode",   SqlDbType.NVarChar, request.CreditCode),
                SqlHelperExtension.CreateInParam("@Description",  SqlDbType.NVarChar, request.Description),
                SqlHelperExtension.CreateInParam("@ValidFrom",    SqlDbType.DateTime, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",      SqlDbType.DateTime, request.ValidTo),
                SqlHelperExtension.CreateInParam("@SalesOrg",     SqlDbType.NVarChar, request.SalesOrg)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateIntegrationPaymentTerms", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }
    #endregion

    #region Billing and Delivery Endpoints

    public async Task<IntegrationBillingReqResponse> SaveBillingDocumentAsync(IntegrationBillingDocumentRequest request)
    {
        IntegrationBillingReqResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                CreateBillingDocument(tc, request);
                response.InvoiceBillingDocumentNumber = request.BillingDocumentNumber;
                response.BillingDate = request.BillingDate;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationDeliveryReqResponse> SaveDeliveryInvoiceDocumentAsync(IntegrationDeliveryDocumentRequest request)
    {
        IntegrationDeliveryReqResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                CreateDeliveryInovoiceDocument(tc, request);
                response.DeliveryDocumentNo = request.DeliveryDocumentNo;
                response.DeliveryDate = request.DeliveryDate;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    private bool CreateBillingDocument(TransactionContext tc, IntegrationBillingDocumentRequest request)
    {
        bool returnValue = false;

        try
        {
            DataTable itemTable = new DataTable();
            itemTable.Columns.Add("MaterialCode", typeof(string));
            itemTable.Columns.Add("Quantity", typeof(decimal));
            itemTable.Columns.Add("UnitOfMeasure", typeof(string));
            itemTable.Columns.Add("BillingAmount", typeof(decimal));

            foreach (var item in request.Items)
            {
                DataRow dr = itemTable.NewRow();
                dr["MaterialCode"] = item.ItemCode;
                dr["Quantity"] = item.Quantity;
                dr["UnitOfMeasure"] = item.UnitOfMeasure;
                dr["BillingAmount"] = item.BillingAmount;
                itemTable.Rows.Add(dr);
            }

            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@BillingNumber",    SqlDbType.NVarChar, request.BillingDocumentNumber),
                SqlHelperExtension.CreateInParam("@SalesOrderNo",     SqlDbType.NVarChar, request.SalesOrderReferenceNumber),
                SqlHelperExtension.CreateInParam("@BillingDate",      SqlDbType.DateTime, request.BillingDate),
                SqlHelperExtension.CreateInParam("@DeliveryNumber",   SqlDbType.NVarChar, request.DeliveryReferenceNumber),
                SqlHelperExtension.CreateInParam("@BillingItems",     SqlDbType.Structured, itemTable)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertBillingDocument", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    

    private bool CreateDeliveryInovoiceDocument(TransactionContext tc, IntegrationDeliveryDocumentRequest request)
    {
        bool returnValue = false;

        try
        {
            DataTable itemTable = new DataTable();
            itemTable.Columns.Add("MaterialCode", typeof(string));
            itemTable.Columns.Add("Quantity", typeof(decimal));
            itemTable.Columns.Add("UnitOfMeasure", typeof(string));

            foreach (var item in request.Items)
            {
                DataRow dr = itemTable.NewRow();
                dr["MaterialCode"]  = item.ItemCode;
                dr["Quantity"]      = item.Quantity;
                dr["UnitOfMeasure"] = item.UnitOfMeasure;
                itemTable.Rows.Add(dr);
            }

            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@DeliveryDocumentNo",                 SqlDbType.NVarChar, request.DeliveryDocumentNo),
                SqlHelperExtension.CreateInParam("@SalesOrderReferenceNumber",          SqlDbType.NVarChar, request.SalesOrderReferenceNumber ),
                SqlHelperExtension.CreateInParam("@DeliveryDate",                       SqlDbType.DateTime, request.DeliveryDate),
                SqlHelperExtension.CreateInParam("@DeliveryStatus",                     SqlDbType.NVarChar, request.DeliveryStatus),
                SqlHelperExtension.CreateInParam("@InvoiceItems",                       SqlDbType.Structured, itemTable)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertPrimarySalesInvoice", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion
    private  IList<string> Validate(IntegrationMaterialPriceRequest request, MaterialPriceTypeEnum priceTypeEnum)
    {
        var errors = new List<string>();

        if (request == null)
        {
            errors.Add("Request cannot be null.");
            return errors;
        }

        switch (priceTypeEnum)
        {
            case MaterialPriceTypeEnum.BasePrice:
                Require(request.SalesOrg, nameof(request.SalesOrg), errors);
                Require(request.DistributionChannel, nameof(request.DistributionChannel), errors);
                Require(request.MaterialCode, nameof(request.MaterialCode), errors);
                Require(request.CalculationType, nameof(request.CalculationType), errors);
                Require(request.PricingUnit, nameof(request.PricingUnit), errors);
                Require(request.UnitOfMeasure, nameof(request.UnitOfMeasure), errors);
                break;

            case MaterialPriceTypeEnum.Discount:
                Require(request.CustomerGroupCode, nameof(request.CustomerGroupCode), errors);
                Require(request.MaterialCode, nameof(request.MaterialCode), errors);
                break;

            case MaterialPriceTypeEnum.SlabBasedDiscount:
                Require(request.CustomerGroupCode, nameof(request.CustomerGroupCode), errors);
                break;

            case MaterialPriceTypeEnum.VatPrice:
                Require(request.MaterialCode, nameof(request.MaterialCode), errors);
                break;

            default:
                errors.Add($"Unsupported Condition Type '{request.ConditionType}'.");
                break;
        }

        return errors;
    }

    private static void Require(string? value, string fieldName, IList<string> errors)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            errors.Add($"{fieldName} is required.");
        }
    }
}
