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

namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Systems
{
	public class ParamTypeService(IOptions<AppSettings> settings) : IParamTypeService
	{
		private readonly AppSettings _settings = settings?.Value;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="settingId"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<LabelSettingResponse> GetLabelSettingAsync(int settingId)
		{
			LabelSettingResponse response = new() { ReturnStatus = 200 };

			try
			{
				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader("SELECT Label01, Label01Req, Label01RegExp, Label02, Label02Req, Label02RegExp, Label03, Label03Req, Label03RegExp,"
						+ " Label04, Label04Req, Label04RegExp, Label05, Label05Req, Label05RegExp, Label06, Label06Req, Label06RegExp, Label07, Label07Req, Label07RegExp, Label08, Label08Req, Label08RegExp,"
						+ " Label09, Label09Req, Label09RegExp, Label10, Label10Req, Label10RegExp, Label11, Label11Req, Label11RegExp, Label12, Label12Req, Label12RegExp, Label13, Label13Req, Label13RegExp,"
						+ " Label14, Label14Req, Label14RegExp, Label15, Label15Req, Label15RegExp, Label16, Label16Req, Label16RegExp, Label17, Label17Req, Label17RegExp, Label18, Label18Req, Label18RegExp,"
						+ " Label19, Label19Req, Label19RegExp, Label20, Label20Req, Label20RegExp, Label21, Label21Req, Label21RegExp, Label22, Label22Req, Label22RegExp, Label23, Label23Req, Label23RegExp,"
						+ " Label24, Label24Req, Label24RegExp, Label25, Label25Req, Label25RegExp, Label26, Label26Req, Label26RegExp, Label27, Label27Req, Label27RegExp, Label28, Label28Req, Label28RegExp,"
						+ " Label29, Label29Req, Label29RegExp, Label30, Label30Req, Label30RegExp, HasAuthProcess FROM LabelSettings WHERE SettingId=%n", settingId);
					if (dr.Read())
					{
						response = new LabelSettingResponse
						{
							Label01 = dr.IsDBNull(0) ? string.Empty : dr.GetString(0),
							Label01Req = dr.IsDBNull(1) ? 0 : dr.GetInt16(1),
							Label01RegExp = dr.IsDBNull(2) ? string.Empty : dr.GetString(2),
							Label02 = dr.IsDBNull(3) ? string.Empty : dr.GetString(3),
							Label02Req = dr.IsDBNull(4) ? 0 : dr.GetInt16(4),
							Label02RegExp = dr.IsDBNull(5) ? string.Empty : dr.GetString(5),
							Label03 = dr.IsDBNull(6) ? string.Empty : dr.GetString(6),
							Label03Req = dr.IsDBNull(7) ? 0 : dr.GetInt16(7),
							Label03RegExp = dr.IsDBNull(8) ? string.Empty : dr.GetString(8),
							Label04 = dr.IsDBNull(9) ? string.Empty : dr.GetString(9),
							Label04Req = dr.IsDBNull(10) ? 0 : dr.GetInt16(10),
							Label04RegExp = dr.IsDBNull(11) ? string.Empty : dr.GetString(11),
							Label05 = dr.IsDBNull(12) ? string.Empty : dr.GetString(12),
							Label05Req = dr.IsDBNull(13) ? 0 : dr.GetInt16(13),
							Label05RegExp = dr.IsDBNull(14) ? string.Empty : dr.GetString(14),
							Label06 = dr.IsDBNull(15) ? string.Empty : dr.GetString(15),
							Label06Req = dr.IsDBNull(16) ? 0 : dr.GetInt16(16),
							Label06RegExp = dr.IsDBNull(17) ? string.Empty : dr.GetString(17),
							Label07 = dr.IsDBNull(18) ? string.Empty : dr.GetString(18),
							Label07Req = dr.IsDBNull(19) ? 0 : dr.GetInt16(19),
							Label07RegExp = dr.IsDBNull(20) ? string.Empty : dr.GetString(20),
							Label08 = dr.IsDBNull(21) ? string.Empty : dr.GetString(21),
							Label08Req = dr.IsDBNull(22) ? 0 : dr.GetInt16(22),
							Label08RegExp = dr.IsDBNull(23) ? string.Empty : dr.GetString(23),
							Label09 = dr.IsDBNull(24) ? string.Empty : dr.GetString(24),
							Label09Req = dr.IsDBNull(25) ? 0 : dr.GetInt16(25),
							Label09RegExp = dr.IsDBNull(26) ? string.Empty : dr.GetString(26),
							Label10 = dr.IsDBNull(27) ? string.Empty : dr.GetString(27),
							Label10Req = dr.IsDBNull(28) ? 0 : dr.GetInt16(28),
							Label10RegExp = dr.IsDBNull(29) ? string.Empty : dr.GetString(29),
							Label11 = dr.IsDBNull(30) ? string.Empty : dr.GetString(30),
							Label11Req = dr.IsDBNull(31) ? 0 : dr.GetInt16(31),
							Label11RegExp = dr.IsDBNull(32) ? string.Empty : dr.GetString(32),
							Label12 = dr.IsDBNull(33) ? string.Empty : dr.GetString(33),
							Label12Req = dr.IsDBNull(34) ? 0 : dr.GetInt16(34),
							Label12RegExp = dr.IsDBNull(35) ? string.Empty : dr.GetString(35),
							Label13 = dr.IsDBNull(36) ? string.Empty : dr.GetString(36),
							Label13Req = dr.IsDBNull(37) ? 0 : dr.GetInt16(37),
							Label13RegExp = dr.IsDBNull(38) ? string.Empty : dr.GetString(38),
							Label14 = dr.IsDBNull(39) ? string.Empty : dr.GetString(39),
							Label14Req = dr.IsDBNull(40) ? 0 : dr.GetInt16(40),
							Label14RegExp = dr.IsDBNull(41) ? string.Empty : dr.GetString(41),
							Label15 = dr.IsDBNull(42) ? string.Empty : dr.GetString(42),
							Label15Req = dr.IsDBNull(43) ? 0 : dr.GetInt16(43),
							Label15RegExp = dr.IsDBNull(44) ? string.Empty : dr.GetString(44),
							Label16 = dr.IsDBNull(45) ? string.Empty : dr.GetString(45),
							Label16Req = dr.IsDBNull(46) ? 0 : dr.GetInt16(46),
							Label16RegExp = dr.IsDBNull(47) ? string.Empty : dr.GetString(47),
							Label17 = dr.IsDBNull(48) ? string.Empty : dr.GetString(48),
							Label17Req = dr.IsDBNull(49) ? 0 : dr.GetInt16(49),
							Label17RegExp = dr.IsDBNull(50) ? string.Empty : dr.GetString(50),
							Label18 = dr.IsDBNull(51) ? string.Empty : dr.GetString(51),
							Label18Req = dr.IsDBNull(52) ? 0 : dr.GetInt16(52),
							Label18RegExp = dr.IsDBNull(53) ? string.Empty : dr.GetString(53),
							Label19 = dr.IsDBNull(54) ? string.Empty : dr.GetString(54),
							Label19Req = dr.IsDBNull(55) ? 0 : dr.GetInt16(55),
							Label19RegExp = dr.IsDBNull(56) ? string.Empty : dr.GetString(56),
							Label20 = dr.IsDBNull(57) ? string.Empty : dr.GetString(57),
							Label20Req = dr.IsDBNull(58) ? 0 : dr.GetInt16(58),
							Label20RegExp = dr.IsDBNull(59) ? string.Empty : dr.GetString(59),
							Label21 = dr.IsDBNull(60) ? string.Empty : dr.GetString(60),
							Label21Req = dr.IsDBNull(61) ? 0 : dr.GetInt16(61),
							Label21RegExp = dr.IsDBNull(62) ? string.Empty : dr.GetString(62),
							Label22 = dr.IsDBNull(63) ? string.Empty : dr.GetString(63),
							Label22Req = dr.IsDBNull(64) ? 0 : dr.GetInt16(64),
							Label22RegExp = dr.IsDBNull(65) ? string.Empty : dr.GetString(65),
							Label23 = dr.IsDBNull(66) ? string.Empty : dr.GetString(66),
							Label23Req = dr.IsDBNull(67) ? 0 : dr.GetInt16(67),
							Label23RegExp = dr.IsDBNull(68) ? string.Empty : dr.GetString(68),
							Label24 = dr.IsDBNull(69) ? string.Empty : dr.GetString(69),
							Label24Req = dr.IsDBNull(70) ? 0 : dr.GetInt16(70),
							Label24RegExp = dr.IsDBNull(71) ? string.Empty : dr.GetString(71),
							Label25 = dr.IsDBNull(72) ? string.Empty : dr.GetString(72),
							Label25Req = dr.IsDBNull(73) ? 0 : dr.GetInt16(73),
							Label25RegExp = dr.IsDBNull(74) ? string.Empty : dr.GetString(74),
							Label26 = dr.IsDBNull(75) ? string.Empty : dr.GetString(75),
							Label26Req = dr.IsDBNull(76) ? 0 : dr.GetInt16(76),
							Label26RegExp = dr.IsDBNull(77) ? string.Empty : dr.GetString(77),
							Label27 = dr.IsDBNull(78) ? string.Empty : dr.GetString(78),
							Label27Req = dr.IsDBNull(79) ? 0 : dr.GetInt16(79),
							Label27RegExp = dr.IsDBNull(80) ? string.Empty : dr.GetString(80),
							Label28 = dr.IsDBNull(81) ? string.Empty : dr.GetString(81),
							Label28Req = dr.IsDBNull(82) ? 0 : dr.GetInt16(82),
							Label28RegExp = dr.IsDBNull(83) ? string.Empty : dr.GetString(83),
							Label29 = dr.IsDBNull(84) ? string.Empty : dr.GetString(84),
							Label29Req = dr.IsDBNull(85) ? 0 : dr.GetInt16(85),
							Label29RegExp = dr.IsDBNull(86) ? string.Empty : dr.GetString(86),
							Label30 = dr.IsDBNull(87) ? string.Empty : dr.GetString(87),
							Label30Req = dr.IsDBNull(88) ? 0 : dr.GetInt16(88),
							Label30RegExp = dr.IsDBNull(89) ? string.Empty : dr.GetString(89),
							HasAuthProcess = !dr.IsDBNull(90) && dr.GetInt16(90) > 0,

							ReturnStatus = 200
						};
					}
					dr.Close();

					tc.End();
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		public async Task<BooleanResponse> SaveLabelSettingAsync(LabelSettingRequest request)
		{
			BooleanResponse response = new() { ReturnStatus = 200 };
			try
			{
				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
				try
				{
					SqlParameter[] p =
					[
						SqlHelperExtension.CreateInParam(pName: "@SettingId", pType: SqlDbType.Int, pValue: request.SettingId),
						SqlHelperExtension.CreateInParam(pName: "@Label01", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label01)),
						SqlHelperExtension.CreateInParam(pName: "@Label01", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label01Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label01", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label01RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label02", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label02)),
						SqlHelperExtension.CreateInParam(pName: "@Label02Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label02Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label02RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label02RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label03", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label03)),
						SqlHelperExtension.CreateInParam(pName: "@Label03Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label03Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label03RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label03RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label04", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label04)),
						SqlHelperExtension.CreateInParam(pName: "@Label04Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label04Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label04RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label04RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label05", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label05)),
						SqlHelperExtension.CreateInParam(pName: "@Label05Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label05Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label05RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label05RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label06", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label06)),
						SqlHelperExtension.CreateInParam(pName: "@Label06Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label06Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label06RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label06RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label07", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label07)),
						SqlHelperExtension.CreateInParam(pName: "@Label07Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label07Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label07RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label07RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label08", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label08)),
						SqlHelperExtension.CreateInParam(pName: "@Label08Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label08Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label08RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label08RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label09", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label09)),
						SqlHelperExtension.CreateInParam(pName: "@Label09Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label09Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label09RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label09RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label10", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label10)),
						SqlHelperExtension.CreateInParam(pName: "@Label10Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label10Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label10RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label10RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label11", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label11)),
						SqlHelperExtension.CreateInParam(pName: "@Label11Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label11Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label11RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label11RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label12", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label12)),
						SqlHelperExtension.CreateInParam(pName: "@Label12Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label12Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label12RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label12RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label13", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label13)),
						SqlHelperExtension.CreateInParam(pName: "@Label13Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label13Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label13RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label13RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label14", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label14)),
						SqlHelperExtension.CreateInParam(pName: "@Label14Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label14Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label14RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label14RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label15", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label15)),
						SqlHelperExtension.CreateInParam(pName: "@Label15Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label15Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label15RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label15RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label16", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label16)),
						SqlHelperExtension.CreateInParam(pName: "@Label16Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label16Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label16RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label16RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label17", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label17)),
						SqlHelperExtension.CreateInParam(pName: "@Label17Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label17Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label17RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label17RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label18", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label18)),
						SqlHelperExtension.CreateInParam(pName: "@Label18Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label18Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label18RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label18RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label19", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label19)),
						SqlHelperExtension.CreateInParam(pName: "@Label19Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label19Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label19RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label19RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label20", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label20)),
						SqlHelperExtension.CreateInParam(pName: "@Label20Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label20Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label20RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label20RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label21", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label21)),
						SqlHelperExtension.CreateInParam(pName: "@Label21Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label21Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label21RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label21RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label22", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label22)),
						SqlHelperExtension.CreateInParam(pName: "@Label22Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label22Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label22RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label22RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label23", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label23)),
						SqlHelperExtension.CreateInParam(pName: "@Label23Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label23Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label23RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label23RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label24", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label24)),
						SqlHelperExtension.CreateInParam(pName: "@Label24Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label24Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label24RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label24RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label25", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label25)),
						SqlHelperExtension.CreateInParam(pName: "@Label25Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label25Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label25RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label25RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label26", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label26)),
						SqlHelperExtension.CreateInParam(pName: "@Label26Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label26Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label26RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label26RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label27", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label27)),
						SqlHelperExtension.CreateInParam(pName: "@Label27Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label27Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label27RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label27RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label28", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label28)),
						SqlHelperExtension.CreateInParam(pName: "@Label28Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label28Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label28RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label28RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label29", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label29)),
						SqlHelperExtension.CreateInParam(pName: "@Label29Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label29Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label29RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label29RegExp)),
						SqlHelperExtension.CreateInParam(pName: "@Label30", pType: SqlDbType.NVarChar, pValue: DataReader.GetNullValue(request.Label30, string.Empty)),
						SqlHelperExtension.CreateInParam(pName: "@Label30Req", pType: SqlDbType.SmallInt, pValue: DataReader.GetNullValue(request.Label30Req)),
						SqlHelperExtension.CreateInParam(pName: "@Label30RegExp", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(request.Label30RegExp, string.Empty)),
					];
					_ = tc.ExecuteNonQuerySp(spName: "dbo.SaveLabelSetting", parameterValues: p);

					tc.End();

					response.Value = true;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="lookupType"></param>
		/// <param name="excludeItemId"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<LookupDataResponse> GetLookupDataAsync(EnumLookupType lookupType, int excludeItemId)
		{
			LookupDataResponse response = new() { Value = [] };
			try
			{
				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: "SELECT ItemId, ItemValue FROM Lookups WHERE ItemType=%n AND ItemId NOT IN(%n) ORDER BY SeqId, ItemValue", (short)lookupType, excludeItemId);
					while (dr.Read())
					{
						LookupData item = new()
						{
							ItemId = dr.GetInt32(0),
							ItemValue = dr.GetString(1)
						};

						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="lookupType"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<LookupDataExtResponse> GetLookupDataExtAsync(EnumLookupType lookupType)
		{
			LookupDataExtResponse response = new() { Value = [] };
			try
			{
				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: "SELECT PkId, ItemId, ItemCode, ItemValue, SeqId FROM Lookups WHERE ItemType=%n ORDER BY SeqId, ItemValue", (short)lookupType);
					while (dr.Read())
					{
						LookupDataExt item = new()
						{
							ItemType = (short)lookupType,
							LookupId = dr.GetInt32(0),
							ItemId = dr.GetInt32(1),
							ItemCode = dr.GetString(2),
							ItemValue = dr.GetString(3),
							SeqId = dr.GetInt16(4)
						};

						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="items"></param>
		/// <param name="ipAddress"></param>
		/// <param name="userId"></param>
		/// <returns></returns>
		/// <exception cref="InvalidOperationException"></exception>
		public async Task<bool> SaveLookupDataAsync(List<LookupDataExt> items, string ipAddress, int userId)
		{
			bool response = false;
			try
			{
				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
				try
				{
					foreach (LookupDataExt item in items)
					{
						SqlParameter[] p =
						[
							SqlHelperExtension.CreateInParam(pName: "@PkId", pType: SqlDbType.Int, pValue: item.LookupId),
							SqlHelperExtension.CreateInParam(pName: "@ItemType", pType: SqlDbType.SmallInt, pValue: item.ItemType),
							SqlHelperExtension.CreateInParam(pName: "@ItemId", pType: SqlDbType.Int, pValue: item.ItemId),
							SqlHelperExtension.CreateInParam(pName: "@ItemCode", pType: SqlDbType.NVarChar, pValue: item.ItemCode, size: 50),
							SqlHelperExtension.CreateInParam(pName: "@ItemValue", pType: SqlDbType.NVarChar, pValue: item.ItemValue, size: 50),
							SqlHelperExtension.CreateInParam(pName: "@SeqId", pType: SqlDbType.SmallInt, pValue: item.SeqId),
							SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
							SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId)
						];
						_ = tc.ExecuteNonQuerySp(spName: "dbo.SaveLookupData", parameterValues: p);
					}
					tc.End();

					response = true;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="locationId"></param>
		/// <param name="deletedBy"></param>
		/// <returns></returns>
		public async Task<bool> DeleteLookupDataAsync(int lookupId, int deletedBy)
		{
			bool returnValue;
			try
			{
				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
				try
				{
					SqlParameter[] p =
					[
						SqlHelperExtension.CreateInParam(pName: "@DeletedBy", pType: SqlDbType.Int, pValue: deletedBy),
						SqlHelperExtension.CreateInParam(pName: "@PkId", pType: SqlDbType.Int, pValue: lookupId)
					];
					_ = tc.ExecuteNonQuerySp(spName: "dbo.DeleteLookupData", parameterValues: p);

					tc.End();

					returnValue = true;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}
			return returnValue;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="txnType"></param>
		/// <param name="typeOfTran"></param>
		/// <returns></returns>
		/// <exception cref="InvalidOperationException"></exception>
		public async Task<SalesTxnTypeResponse> GetSalesTxnTypesAsync(int txnType, int typeOfTran)
		{
			SalesTxnTypeResponse response = new() { Value = [] };
			try
			{
				string commandText;
				if (txnType == 1)
				{
					if (typeOfTran == 1)
						commandText = "SELECT TranTypeId, Description, TxnEffect FROM Sales.SalesTranTypes WHERE TranType=1 AND TranTypeId IN(1,2)";
					else
						commandText = "SELECT TranTypeId, Description, TxnEffect FROM Sales.SalesTranTypes WHERE TranType=1 AND IsPredefined=0";
				}
				else
				{
					if (typeOfTran == 1)
						commandText = "SELECT TranTypeId, Description, TxnEffect FROM Sales.SalesTranTypes WHERE TranType=2 AND TranTypeId IN(1,2,3)";
					else
						commandText = "SELECT TranTypeId, Description, TxnEffect FROM Sales.SalesTranTypes WHERE TranType=2 AND IsPredefined=0";
				}


				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: commandText);
					while (dr.Read())
					{
						SalesTxnType item = new()
						{
							TranTypeId = dr.GetInt32(0),
							Description = dr.GetString(1),
							Side = dr.GetString(2).Equals(value: "C", comparisonType: StringComparison.OrdinalIgnoreCase) ? "Increase" : "Decrease"
						};
						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="inventoryTypeId"></param>
		/// <param name="productCode"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<ProdByInvTypeAndCodeResponse> GetProductByCodeAsync(int inventoryTypeId, string productCode)
		{
			ProdByInvTypeAndCodeResponse response = new();
			try
			{
				string commandText;
				if (inventoryTypeId == 4)
				{
					commandText = SQLParser.MakeSQL("SELECT A.FAItemId, A.Code, A.Name, CAST(0 as money) Price, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode, 'Fixed Assets' InventoryTypeName"
					  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
					  + " WHERE (A.Status&8)=8 AND A.Code=%s", productCode);
				}
				else
				{
					commandText = SQLParser.MakeSQL("SELECT A.ProductId, A.Code, A.Name, CAST(0 as money) Price, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, B.InventoryTypeName"
					  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
					  + " WHERE A.Code=%s AND (A.Status&8)=8 AND B.InventoryTypeId=%n", productCode, inventoryTypeId);
				}

				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: commandText);
					if (dr.Read())
					{
						response = new()
						{
							InventoryTypeId = inventoryTypeId,
							ProductId = dr.GetInt32(0),
							ProductCode = dr.GetString(1),
							ProductName = dr.GetString(2),
							Price = dr.GetDecimal(3),
							VatRate = dr.GetDecimal(4),
							AitRate = dr.GetDecimal(5),
							AstOrGLCode = dr.GetString(6),
							ExpOrDepGLCode = dr.GetString(7),
							InventoryType = dr.GetString(8)
						};
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="inventoryTypeId"></param>
		/// <param name="criteria"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<ProdByInvTypeResponse> GetProductsAsync(int inventoryTypeId, string criteria)
		{
			ProdByInvTypeResponse response = new() { Value = [] };
			try
			{
				string commandText;
				if (inventoryTypeId == 4)
				{
					if (!string.IsNullOrEmpty(criteria))
					{
						criteria = criteria.Replace("'", "''");
						commandText = string.Format("SELECT A.FAItemId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, CAST(0 as money) Price, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
						  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
						  + " WHERE (A.Status&8)=8 AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.GLCode LIKE '%{0}%' OR C.DeprnGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria);
					}
					else
					{
						commandText = "SELECT A.FAItemId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, CAST(0 as money) Price, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
						  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
						  + " WHERE (A.Status&8)=8";
					}
				}
				else
				{
					if (!string.IsNullOrEmpty(criteria))
					{
						criteria = criteria.Replace("'", "''");
						commandText = string.Format("SELECT A.ProductId, A.Code, A.Name, B.InventoryTypeName, CAST(0 as money) Price, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
						  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
						  + " WHERE (A.Status&8)=8 AND B.InventoryTypeId={1} AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria, inventoryTypeId);
					}
					else
					{
						commandText = SQLParser.MakeSQL("SELECT A.ProductId, A.Code, A.Name, B.InventoryTypeName, CAST(0 as money) Price, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
						  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
						  + " WHERE (A.Status&8)=8 AND B.InventoryTypeId=%n", inventoryTypeId);
					}
				}

				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: commandText);
					while (dr.Read())
					{
						ProdByInvType item = new()
						{
							InventoryTypeId = inventoryTypeId,
							ProductId = dr.GetInt32(0),
							ProductCode = dr.GetString(1),
							ProductName = dr.GetString(2),
							InventoryType = dr.GetString(3),
							Price = dr.GetDecimal(4),
							VatRate = dr.GetDecimal(5),
							AitRate = dr.GetDecimal(6),
							AstOrGLCode = dr.GetString(7),
							ExpOrDepGLCode = dr.GetString(8)
						};

						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="criteria"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<ProdByInvTypeResponse> GetFASparePartsAsync(string criteria)
		{
			ProdByInvTypeResponse response = new() { Value = [] };
			try
			{
				string commandText;
				if (!string.IsNullOrEmpty(criteria))
				{
					criteria = criteria.Replace("'", "''");
					commandText = string.Format("SELECT A.FAItemId, A.Code, A.Name, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
					  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
					  + " WHERE (A.Status&8)=8 AND A.IsSparePart=1 AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.GLCode LIKE '%{0}%' OR C.DeprnGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria);
				}
				else
				{
					commandText = "SELECT A.FAItemId, A.Code, A.Name, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
					  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
					  + " WHERE (A.Status&8)=8 AND A.IsSparePart=1";
				}

				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: commandText);
					while (dr.Read())
					{
						ProdByInvType item = new()
						{
							Price = 0,
							InventoryTypeId = 4,
							InventoryType = "Fixed Assets",

							ProductId = dr.GetInt32(0),
							ProductCode = dr.GetString(1),
							ProductName = dr.GetString(2),
							VatRate = dr.GetDecimal(3),
							AitRate = dr.GetDecimal(4),
							AstOrGLCode = dr.GetString(5),
							ExpOrDepGLCode = dr.GetString(6)
						};

						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="inventoryTypeIds"></param>
		/// <param name="materialOnly"></param>
		/// <param name="criteria"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<ProdByInvTypeResponse> GetProductsExtAsync(List<int> inventoryTypeIds, bool materialOnly, string criteria)
		{
			ProdByInvTypeResponse response = new() { Value = [] };
			try
			{
				#region Remove No filter item

				int idx = inventoryTypeIds.FindIndex(x => x == 0);
				if (idx != 0)
				{
					inventoryTypeIds.Remove(idx);
				}

				#endregion

				string commandText;
				if (inventoryTypeIds.Count == 0)
				{
					if (!string.IsNullOrEmpty(criteria))
					{
						criteria = criteria.Replace("'", "''");
						commandText = string.Format("SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							+ " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
							+ " WHERE (A.Status&8)=8 AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.GLCode LIKE '%{0}%' OR C.DeprnGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
							+ " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
							+ " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
							+ " WHERE (A.Status&8)=8 AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria);
					}
					else
					{
						commandText = "SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							+ " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId WHERE (A.Status&8)=8"
							+ " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
							+ " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId WHERE (A.Status&8)=8";
					}
				}
				else
				{
					if (!string.IsNullOrEmpty(criteria))
					{
						criteria = criteria.Replace("'", "''");
						if (inventoryTypeIds.Contains(4))
						{
							commandText = string.Format("SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId"
							  + " WHERE (A.Status&8)=8 AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.GLCode LIKE '%{0}%' OR C.DeprnGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
							  + " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
							  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
							  + " WHERE (A.Status&8)=8 AND B.InventoryTypeId IN({1}) AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria, string.Join(',', inventoryTypeIds));
						}
						else
						{
							if (materialOnly)
							{
								commandText = string.Format("SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
								  + " WHERE (A.Status&8)=8 AND B.ItemTypeId=2 AND B.InventoryTypeId IN({1}) AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria, string.Join(',', inventoryTypeIds));
							}
							else
							{
								commandText = string.Format("SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
								  + " WHERE (A.Status&8)=8 AND B.InventoryTypeId IN({1}) AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')", criteria, string.Join(',', inventoryTypeIds));
							}
						}
					}
					else
					{
						if (inventoryTypeIds.Contains(4))
						{
							commandText = "SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId WHERE (A.Status&8)=8"
							  + " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
							  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
							  + $" WHERE (A.Status&8)=8 AND B.InventoryTypeId IN({string.Join(',', inventoryTypeIds)})";
						}
						else
						{
							if (materialOnly)
							{
								commandText = "SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
								  + $" WHERE (A.Status&8)=8 AND B.ItemTypeId=2 AND B.InventoryTypeId IN({string.Join(',', inventoryTypeIds)})";
							}
							else
							{
								commandText = "SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId"
								  + $" WHERE (A.Status&8)=8 AND B.InventoryTypeId IN({string.Join(',', inventoryTypeIds)})";
							}
						}
					}
				}

				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: commandText);
					while (dr.Read())
					{
						ProdByInvType item = new()
						{
							InventoryTypeId = dr.GetInt32(0),
							ProductId = dr.GetInt32(1),
							ProductCode = dr.GetString(2),
							ProductName = dr.GetString(3),
							InventoryType = dr.GetString(4),
							Price = dr.GetDecimal(5),
							VatRate = dr.GetDecimal(6),
							AitRate = dr.GetDecimal(7),
							AstOrGLCode = dr.GetString(8),
							ExpOrDepGLCode = dr.GetString(9)
						};

						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="storeId"></param>
		/// <param name="stockOf"></param>
		/// <param name="stockOnly"></param>
		/// <param name="inventoryTypeIds"></param>
		/// <param name="materialOnly"></param>
		/// <param name="criteria"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public async Task<ProdByInvTypeExtResponse> GetProductsStockAsync(int storeId, int stockOf, bool stockOnly, List<int> inventoryTypeIds, bool materialOnly, string criteria)
		{
			ProdByInvTypeExtResponse response = new() { Value = [] };
			try
			{
				#region Remove No filter item

				for (int idx = 0; idx < inventoryTypeIds.Count; idx++)
				{
					if (inventoryTypeIds[idx] == 0)
					{
						inventoryTypeIds.Remove(idx);
						break;
					}
				}

				#endregion

				string stockFld;
				string storeFld = storeId > 0 ? $" AND D.StoreId={storeId}" : "";
				switch (stockOf)
				{
					case 4:
						stockFld = "SUM(D.BkdBalance) Balance";
						storeFld += stockOnly ? " AND D.BkdBalance>0" : "";
						break;

					case 3:
						stockFld = "SUM(D.ExpBalance) Balance";
						storeFld += stockOnly ? " AND D.ExpBalance>0" : "";
						break;

					case 2:
						stockFld = "SUM(D.DmgBalance) Balance";
						storeFld += stockOnly ? " AND D.DmgBalance>0" : "";
						break;

					default:
						stockFld = "SUM(D.SndBalance) Balance";
						storeFld += stockOnly ? " AND D.SndBalance>0" : "";
						break;
				}

				string commandText;
				if (inventoryTypeIds.Count == 0)
				{
					if (!string.IsNullOrEmpty(criteria))
					{
						criteria = criteria.Replace("'", "''");
						commandText = string.Format("SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode, {1}"
							+ " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId INNER JOIN ProductsStock D ON A.FAItemId=D.FAItemId"
							+ " WHERE (A.Status&8)=8{2} AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.GLCode LIKE '%{0}%' OR C.DeprnGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
							+ " GROUP BY A.FAItemId, A.Code, A.Name, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							+ " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {1}"
							+ " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
							+ " WHERE (A.Status&8)=8{2} AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
							+ " GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode", criteria, stockFld, storeFld);
					}
					else
					{
						commandText = string.Format("SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode, {0}"
							+ " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId INNER JOIN ProductsStock D ON A.FAItemId=D.FAItemId"
							+ " WHERE (A.Status&8)=8{1} GROUP BY A.FAItemId, A.Code, A.Name, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							+ " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {0}"
							+ " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId WHERE (A.Status&8)=8{1}"
							+ " GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode", stockFld, storeFld);
					}
				}
				else
				{
					if (!string.IsNullOrEmpty(criteria))
					{
						criteria = criteria.Replace("'", "''");
						if (inventoryTypeIds.Contains(4))
						{
							commandText = string.Format("SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode, {1}"
							  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId INNER JOIN ProductsStock D ON A.FAItemId=D.FAItemId"
							  + " WHERE (A.Status&8)=8{3} AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.GLCode LIKE '%{0}%' OR C.DeprnGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
							  + " GROUP BY A.FAItemId, A.Code, A.Name, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							  + " UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {1}"
							  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
							  + " WHERE (A.Status&8)=8{3} AND B.InventoryTypeId IN({2}) AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
							  + " GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode", criteria, stockFld, string.Join(',', inventoryTypeIds), storeFld);
						}
						else
						{
							if (materialOnly)
							{
								commandText = string.Format("SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {1}"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
								  + " WHERE (A.Status&8)=8 AND B.ItemTypeId=2 AND B.InventoryTypeId IN({2}){3} AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
								  + " GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode", criteria, stockFld, string.Join(',', inventoryTypeIds), storeFld);
							}
							else
							{
								commandText = string.Format("SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {1}"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
								  + " WHERE (A.Status&8)=8 AND B.InventoryTypeId IN({2}){3} AND (A.Code LIKE '%{0}%' OR A.Name LIKE '%{0}%' OR B.AssetGLCode LIKE '%{0}%' OR B.ExpenseGLCode LIKE '%{0}%' OR B.Code LIKE '%{0}%' OR B.Name LIKE '%{0}%')"
								  + " GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode", criteria, stockFld, string.Join(',', inventoryTypeIds), storeFld);
							}
						}
					}
					else
					{
						if (inventoryTypeIds.Contains(4))
						{
							commandText = $"SELECT 4 InventoryTypeId, A.FAItemId ProductId, A.Code, A.Name, 'Fixed Assets' InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode, {stockFld}"
							  + " FROM FAItems A INNER JOIN FACategories B ON A.FACategId=B.FACategId INNER JOIN FATypes C ON A.FATypeId=C.FATypeId INNER JOIN ProductsStock D ON A.FAItemId=D.FAItemId"
							  + $" WHERE (A.Status&8)=8{storeFld} GROUP BY A.FAItemId, A.Code, A.Name, A.AvgPrice, B.VATRate, B.AITRate, B.GLCode, C.DeprnGLCode"
							  + $" UNION ALL SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {stockFld}"
							  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
							  + $" WHERE (A.Status&8)=8{storeFld} AND B.InventoryTypeId IN({string.Join(',', inventoryTypeIds)}) GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode";
						}
						else
						{
							if (materialOnly)
							{
								commandText = $"SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {stockFld}"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
								  + $" WHERE (A.Status&8)=8 AND B.ItemTypeId=2{storeFld} AND B.InventoryTypeId IN({string.Join(',', inventoryTypeIds)}) GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode";
							}
							else
							{
								commandText = $"SELECT B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode, {stockFld}"
								  + " FROM Products A INNER JOIN ProductTypes B ON A.ProdTypeId=B.ProdTypeId INNER JOIN ProductsStock D ON A.ProductId=D.ProductId"
								  + $" WHERE (A.Status&8)=8{storeFld} AND B.InventoryTypeId IN({string.Join(',', inventoryTypeIds)}) GROUP BY B.InventoryTypeId, A.ProductId, A.Code, A.Name, B.InventoryTypeName, A.AvgPrice, B.VATRate, B.AITRate, B.AssetGLCode, B.ExpenseGLCode";
							}
						}
					}
				}

				using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
				try
				{
					using IDataReader dr = tc.ExecuteReader(commandText: commandText);
					while (dr.Read())
					{
						ProdByInvTypeExt item = new()
						{
							StoreId = storeId,
							InventoryTypeId = dr.GetInt32(0),
							ProductId = dr.GetInt32(1),
							ProductCode = dr.GetString(2),
							ProductName = dr.GetString(3),
							InventoryType = dr.GetString(4),
							Price = dr.GetDecimal(5),
							VatRate = dr.GetDecimal(6),
							AitRate = dr.GetDecimal(7),
							AstOrGLCode = dr.GetString(8),
							ExpOrDepGLCode = dr.GetString(9),
							Stock = dr.GetDecimal(10)
						};

						response.Value.Add(item);
					}
					dr.Close();

					tc.End();
					response.ReturnStatus = 200;
				}
				catch (Exception ie)
				{
					tc?.HandleError();

					throw DBCustomError.GenerateCustomError(ie);
				}
			}
			catch (Exception e)
			{
				throw new InvalidOperationException(e.Message, e);
			}

			return response;
		}
	}
}