/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>
*/

package engine

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/cgrates/birpc"
	"github.com/cgrates/birpc/context"
	"github.com/cgrates/cgrates/config"
	"github.com/cgrates/cgrates/guardian"
	"github.com/cgrates/cgrates/utils"
	"github.com/cgrates/rpcclient"
)

type clMock func(_ string, _ any, _ any) error

func (c clMock) Call(ctx *context.Context, m string, a any, r any) error {
	return c(m, a, r)
}

func TestCDRSV1ProcessCDRNoTenant(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().AttributeSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	clMock := clMock(func(_ string, args any, reply any) error {
		rply, cancast := reply.(*AttrSProcessEventReply)
		if !cancast {
			return fmt.Errorf("can't cast")
		}
		newArgs, cancast := args.(*utils.CGREvent)
		if !cancast {
			return fmt.Errorf("can't cast")
		}
		if newArgs.Tenant == utils.EmptyString {
			return fmt.Errorf("Tenant is missing")
		}
		*rply = AttrSProcessEventReply{
			AlteredFields: []string{utils.AccountField},
			CGREvent: &utils.CGREvent{
				ID:   "TestBiRPCv1AuthorizeEventNoTenant",
				Time: utils.TimePointer(time.Date(2016, time.January, 5, 18, 30, 49, 0, time.UTC)),
				Event: map[string]any{
					"Account":     "1002",
					"Category":    "call",
					"Destination": "1003",
					"OriginHost":  "local",
					"OriginID":    "123456",
					"ToR":         "*voice",
					"Usage":       "10s",
				},
			},
		}
		return nil
	})
	chanClnt := make(chan birpc.ClientConnector, 1)
	chanClnt <- clMock
	connMngr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanClnt,
	})
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), connMngr)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMngr,
		cdrDb:   idb,
		dm:      dm,
	}
	cdr := &CDRWithAPIOpts{ // no tenant, take the default
		CDR: &CDR{
			CGRID:       "Cdr1",
			OrderID:     123,
			ToR:         utils.MetaVoice,
			OriginID:    "OriginCDR1",
			OriginHost:  "192.168.1.1",
			Source:      "test",
			RequestType: utils.MetaRated,
			Category:    "call",
			Account:     "1001",
			Subject:     "1001",
			Destination: "+4986517174963",
			RunID:       utils.MetaDefault,
			Usage:       time.Duration(0),
			ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
			Cost:        1.01,
		},
	}
	var reply string
	if err := cdrs.V1ProcessCDR(context.Background(), cdr, &reply); err != nil {
		t.Error(err)
	}
}

func TestCDRSV1ProcessEventNoTenant(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	clMock := clMock(func(_ string, args any, reply any) error {
		rply, cancast := reply.(*[]*ChrgSProcessEventReply)
		if !cancast {
			return fmt.Errorf("can't cast")
		}
		newArgs, cancast := args.(*utils.CGREvent)
		if !cancast {
			return fmt.Errorf("can't cast")
		}
		if newArgs.Tenant == utils.EmptyString {
			return fmt.Errorf("Tenant is missing")
		}
		*rply = []*ChrgSProcessEventReply{}
		return nil
	})
	chanClnt := make(chan birpc.ClientConnector, 1)
	chanClnt <- clMock
	connMngr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanClnt,
	})
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), connMngr)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMngr,
		cdrDb:   idb,
		dm:      dm,
	}
	args := &ArgV1ProcessEvent{
		Flags: []string{utils.MetaChargers},
		CGREvent: utils.CGREvent{
			ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute,
			},
		},
	}
	var reply string

	if err := cdrs.V1ProcessEvent(context.Background(), args, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Errorf("expected %v,received %v", utils.OK, reply)
	}
}

func TestCDRSV1V1ProcessExternalCDRNoTenant(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	clMock := clMock(func(_ string, args any, reply any) error {
		rply, cancast := reply.(*[]*ChrgSProcessEventReply)
		if !cancast {
			return fmt.Errorf("can't cast")
		}
		newArgs, cancast := args.(*utils.CGREvent)
		if !cancast {
			return fmt.Errorf("can't cast")
		}
		if newArgs.Tenant == utils.EmptyString {
			return fmt.Errorf("Tenant is missing")
		}
		*rply = []*ChrgSProcessEventReply{}
		return nil
	})
	chanClnt := make(chan birpc.ClientConnector, 1)
	chanClnt <- clMock
	connMngr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanClnt,
	})
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), connMngr)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMngr,
		cdrDb:   idb,
		dm:      dm,
	}

	args := &ExternalCDRWithAPIOpts{
		ExternalCDR: &ExternalCDR{
			ToR:         utils.MetaVoice,
			OriginID:    "testDspCDRsProcessExternalCDR",
			OriginHost:  "127.0.0.1",
			Source:      utils.UnitTest,
			RequestType: utils.MetaRated,
			Tenant:      "cgrates.org",
			Category:    "call",
			Account:     "1003",
			Subject:     "1003",
			Destination: "1001",
			SetupTime:   "2014-08-04T13:00:00Z",
			AnswerTime:  "2014-08-04T13:00:07Z",
			Usage:       "1s",
			ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
		},
	}
	var reply string

	if err := cdrs.V1ProcessExternalCDR(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}
}

func TestArgV1ProcessClone(t *testing.T) {
	attr := &ArgV1ProcessEvent{
		Flags: []string{"flg,flg2,flg3"},
		CGREvent: utils.CGREvent{
			ID:   "TestBiRPCv1AuthorizeEventNoTenant",
			Time: utils.TimePointer(time.Date(2016, time.January, 5, 18, 30, 49, 0, time.UTC)),
			Event: map[string]any{
				"Account":     "1002",
				"Category":    "call",
				"Destination": "1003",
				"OriginHost":  "local",
				"OriginID":    "123456",
				"ToR":         "*voice",
				"Usage":       "10s",
			},
		},
		clnb: true,
	}
	if val := attr.Clone(); reflect.DeepEqual(attr, val) {
		t.Errorf("expected %v,received %v", utils.ToJSON(val), utils.ToJSON(attr))
	}

}

func TestCDRV1CountCDRs(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.GeneralCfg().DefaultTimezone = "UTC"
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: nil,
		cdrDb:   idb,
		dm:      dm,
	}
	args := &utils.RPCCDRsFilterWithAPIOpts{

		RPCCDRsFilter: &utils.RPCCDRsFilter{},
		Tenant:        "cgrates.org",
		APIOpts:       map[string]any{},
	}

	i := int64(3)
	if err := cdrS.V1GetCDRsCount(context.Background(), args, &i); err != nil {
		t.Error(err)
	}
}
func TestV1CountCDRsErr(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.GeneralCfg().DefaultTimezone = "UTC"
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: nil,
		cdrDb:   idb,
		dm:      dm,
	}
	args := &utils.RPCCDRsFilterWithAPIOpts{
		RPCCDRsFilter: &utils.RPCCDRsFilter{
			Accounts:       []string{"1001"},
			RunIDs:         []string{utils.MetaDefault},
			SetupTimeStart: "fdd",
		},
		Tenant: "cgrates.org",
		APIOpts: map[string]any{
			utils.OptsAPIKey: "cdrs12345",
		},
	}
	i := utils.Int64Pointer(23)
	if err := cdrS.V1GetCDRsCount(context.Background(), args, i); err == nil {
		t.Error(err)
	}
}
func TestV1RateCDRs(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.GeneralCfg().DefaultTimezone = "UTC"
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: nil,
		cdrDb:   idb,
		dm:      dm,
	}
	arg := &ArgRateCDRs{
		Flags:         []string{utils.MetaAttributes, utils.MetaStats, utils.MetaExport, utils.MetaStore, utils.OptsThresholdS, utils.MetaThresholds, utils.MetaStats, utils.OptsChargerS, utils.MetaChargers, utils.OptsRALs, utils.MetaRALs, utils.OptsRerate, utils.MetaRerate, utils.OptsRefund, utils.MetaRefund},
		Tenant:        "cgrates.rg",
		RPCCDRsFilter: utils.RPCCDRsFilter{},
		APIOpts:       map[string]any{},
	}

	var reply string
	if err := cdrS.V1RateCDRs(context.Background(), arg, &reply); err == nil {
		t.Error(err)
	}

}

func TestCDRServerThdsProcessEvent(t *testing.T) {
	clMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ThresholdSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {

				rpl := &[]string{"event"}

				*reply.(*[]string) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- clMock
	cfg := config.NewDefaultCGRConfig()
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.ThresholdSConnsCfg): clientconn,
	})
	cfg.CdrsCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.ThreshSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMgr,
		cdrDb:   db,
		dm:      dm,
	}
	crgEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "id",
		Time:   utils.TimePointer(time.Date(2019, 12, 1, 15, 0, 0, 0, time.UTC)),
	}

	if err := cdrS.thdSProcessEvent(crgEv); err != nil {
		t.Error(err)
	}

}
func TestCDRServerStatSProcessEvent(t *testing.T) {
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.StatSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {

				rpl := &[]string{"status"}

				*reply.(*[]string) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	cfg := config.NewDefaultCGRConfig()
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.StatSConnsCfg): clientconn,
	})
	cfg.CdrsCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.StatSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	fltrs := NewFilterS(cfg, connMgr, dm)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		dm:      dm,
		filterS: fltrs,
		cdrDb:   db,
		connMgr: connMgr,
	}
	crgEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "id",
		Time:   utils.TimePointer(time.Date(2019, 12, 1, 15, 0, 0, 0, time.UTC)),
	}

	if err := cdrS.statSProcessEvent(crgEv); err != nil {
		t.Error(err)
	}
}

func TestCDRServerEesProcessEvent(t *testing.T) {
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.EeSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				rpls := &map[string]map[string]any{
					"eeS": {
						"process": "event",
					},
				}
				*reply.(*map[string]map[string]any) = *rpls

				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock

	cfg := config.NewDefaultCGRConfig()
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.EEsConnsCfg): clientconn,
	})
	cfg.CdrsCfg().EEsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.EEsConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), connMgr)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}

	cgrEv := &CGREventWithEeIDs{
		EeIDs: []string{"ees"},
		CGREvent: &utils.CGREvent{
			Tenant: "cgrates.org",
			ID:     "id",
			Time:   utils.TimePointer(time.Date(2019, 12, 1, 15, 0, 0, 0, time.UTC)),
		},
	}
	if err := cdrS.eeSProcessEvent(cgrEv); err != nil {
		t.Error(err)
	}

}

func TestCDRefundEventCost(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderRefundIncrements: func(ctx *context.Context, args, reply any) error {
				return nil
			},
		},
	}
	ec := &EventCost{
		CGRID: "event",
		RunID: "runid",
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.ResponderRefundIncrements): clientconn,
	})
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.ResponderRefundIncrements)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	if _, err := cdrS.refundEventCost(ec, "*postpaid", "tor"); err != nil {
		t.Error(err)
	}
}

func TestGetCostFromRater(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)

	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{

			utils.ResponderDebit: func(ctx *context.Context, args, reply any) error {
				rpl := &CallCost{
					Category: "category",
					Tenant:   "cgrates",
				}
				*reply.(*CallCost) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg): clientconn,
	})
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMgr,
		cdrDb:   db,
		dm:      dm,
	}
	cd := &CDR{
		Category:    "category",
		Tenant:      "cgrates.org",
		RequestType: utils.PseudoPrepaid,
	}
	cdr := &CDRWithAPIOpts{
		CDR:     cd,
		APIOpts: map[string]any{},
	}
	exp := &CallCost{
		Category: "category",
		Tenant:   "cgrates",
	}
	if val, err := cdrS.getCostFromRater(cdr); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(exp, val) {
		t.Errorf("expected %+v ,received %+v", utils.ToJSON(exp), utils.ToJSON(val))
	}
}

func TestRefundEventCost(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderRefundIncrements: func(ctx *context.Context, args, reply any) error {
				rpl := &Account{}
				*reply.(*Account) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg): clientconn,
	})
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	ec := &EventCost{
		CGRID:     "cgrid",
		RunID:     "rnID",
		StartTime: time.Date(2022, 12, 1, 11, 0, 0, 0, time.UTC),
		Charges: []*ChargingInterval{
			{
				CompressFactor: 2,
				Increments: []*ChargingIncrement{
					{
						Usage: 10 * time.Minute,
						Cost:  20,
					}, {
						Usage: 5 * time.Minute,
						Cost:  15,
					},
				},
			}, {},
		},
	}
	if val, err := cdrS.refundEventCost(ec, utils.MetaPrepaid, "tor"); err != nil {
		t.Error(err)
	} else if !val {
		t.Error("expected true")
	}
}

func TestCDRSV2ProcessEvent(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1

	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	clMock := clMock(func(_ string, args any, reply any) error {

		return nil
	})
	chanClnt := make(chan birpc.ClientConnector, 1)
	chanClnt <- clMock
	connMngr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanClnt,
	})
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), connMngr)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMngr,
		cdrDb:   idb,
		dm:      dm,
	}

	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	args := &ArgV1ProcessEvent{
		Flags: []string{utils.MetaChargers},
		CGREvent: utils.CGREvent{
			ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute,
			},
		},
	}
	evs := &[]*utils.EventWithFlags{}

	if err := cdrs.V2ProcessEvent(context.Background(), args, evs); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{
		Result: evs,
		Error:  nil}
	cacheKey := utils.ConcatenatedKey(utils.CDRsV2ProcessEvent, args.CGREvent.ID)
	rcv, has := Cache.Get(utils.CacheRPCResponses, cacheKey)
	if !has {
		t.Error("expected value")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))

	}

}
func TestCDRSV2ProcessEventCacheSet(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: nil,
		cdrDb:   idb,
		dm:      dm,
	}
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	args := &ArgV1ProcessEvent{
		Flags: []string{utils.MetaChargers},
		CGREvent: utils.CGREvent{
			ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute,
			},
		},
	}
	evs := &[]*utils.EventWithFlags{}
	Cache.Set(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV2ProcessEvent, args.CGREvent.ID),
		&utils.CachedRPCResponse{Result: evs, Error: nil},
		nil, true, utils.NonTransactional)

	if err := cdrs.V2ProcessEvent(context.Background(), args, evs); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{Result: evs, Error: nil}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV2ProcessEvent, args.CGREvent.ID))
	if !has {
		t.Error("expected to have a values")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}

}

func TestCDRSV1ProcessEvent(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1

	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	clMock := clMock(func(_ string, args any, reply any) error {

		return nil
	})
	chanClnt := make(chan birpc.ClientConnector, 1)
	chanClnt <- clMock
	connMngr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanClnt,
	})
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), connMngr)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMngr,
		cdrDb:   idb,
		dm:      dm,
	}

	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	args := &ArgV1ProcessEvent{
		Flags: []string{utils.MetaChargers},
		CGREvent: utils.CGREvent{
			ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute,
			},
		},
	}
	reply := utils.StringPointer("result")

	if err := cdrs.V1ProcessEvent(context.Background(), args, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{
		Result: reply,
		Error:  nil}
	cacheKey := utils.ConcatenatedKey(utils.CDRsV1ProcessEvent, args.CGREvent.ID)
	rcv, has := Cache.Get(utils.CacheRPCResponses, cacheKey)
	if !has {
		t.Error("expected value")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))

	}

}
func TestCDRSV1ProcessEventCacheSet(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		connMgr: nil,
		cdrDb:   idb,
		dm:      dm,
	}
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	args := &ArgV1ProcessEvent{
		Flags: []string{utils.MetaChargers},
		CGREvent: utils.CGREvent{
			ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute,
			},
		},
	}
	reply := utils.StringPointer("result")
	Cache.Set(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1ProcessEvent, args.CGREvent.ID),
		&utils.CachedRPCResponse{Result: reply, Error: nil},
		nil, true, utils.NonTransactional)

	if err := cdrs.V1ProcessEvent(context.Background(), args, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{Result: reply, Error: nil}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1ProcessEvent, args.CGREvent.ID))
	if !has {
		t.Error("expected to have a values")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}

}

func TestV1ProcessEvent(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	defer func() {
		config.SetCgrConfig(cfg)
	}()
	cfg.CdrsCfg().AttributeSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.AttributeSConnsCfg)}
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder)}
	cfg.CdrsCfg().EEsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.EEsConnsCfg)}
	cfg.CdrsCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	cfg.CdrsCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)}
	cfg.CdrsCfg().StoreCdrs = true
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				rpl := &AttrSProcessEventReply{
					AlteredFields: []string{"*req.OfficeGroup"},
					CGREvent: &utils.CGREvent{
						Event: map[string]any{
							utils.CGRID: "cgrid",
						},
					},
				}
				*reply.(*AttrSProcessEventReply) = *rpl

				return nil
			},
			utils.ChargerSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				rpl := []*ChrgSProcessEventReply{
					{
						ChargerSProfile:    "chrgs1",
						AttributeSProfiles: []string{"attr1", "attr2"},
						CGREvent: &utils.CGREvent{
							Event: map[string]any{
								utils.CGRID: "cgrid2",
							},
						},
					},
				}
				*reply.(*[]*ChrgSProcessEventReply) = rpl
				return nil
			},
			utils.ResponderRefundIncrements: func(ctx *context.Context, args, reply any) error {
				rpl := &Account{
					ID: "cgrates.org:1001",
					BalanceMap: map[string]Balances{
						utils.MetaMonetary: {
							&Balance{Value: 20},
						}}}
				*reply.(*Account) = *rpl
				return nil
			},
			utils.ResponderDebit: func(ctx *context.Context, args, reply any) error {
				rpl := &CallCost{}
				*reply.(*CallCost) = *rpl
				return nil
			},
			utils.ResponderGetCost: func(ctx *context.Context, args, reply any) error {
				rpl := &CallCost{}
				*reply.(*CallCost) = *rpl
				return nil
			},
			utils.EeSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				rpl := &map[string]map[string]any{}
				*reply.(*map[string]map[string]any) = *rpl
				return nil
			},
			utils.ThresholdSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				rpl := &[]string{}
				*reply.(*[]string) = *rpl
				return nil
			},
			utils.StatSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				rpl := &[]string{}
				*reply.(*[]string) = *rpl
				return nil
			},
		},
	}
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.AttributeSConnsCfg): clientconn,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):       clientconn,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder):      clientconn,
		utils.ConcatenatedKey(utils.MetaInternal, utils.EEsConnsCfg):        clientconn,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds):     clientconn,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats):          clientconn,
	})

	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	arg := &ArgV1ProcessEvent{
		Flags: []string{utils.MetaAttributes, utils.MetaStats, utils.MetaExport, utils.MetaStore, utils.OptsThresholdS, utils.MetaThresholds, utils.MetaStats, utils.OptsChargerS, utils.MetaChargers, utils.OptsRALs, utils.MetaRALs, utils.OptsRerate, utils.MetaRerate, utils.OptsRefund, utils.MetaRefund},
		CGREvent: utils.CGREvent{
			ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute,
			},
		},
	}
	var reply string
	if err := cdrS.V1ProcessEvent(context.Background(), arg, &reply); err == nil {
		t.Error(err)
	}
}
func TestCdrprocessEventsErrLog(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	buf := new(bytes.Buffer)
	setlog := func(b *bytes.Buffer) {
		utils.Logger.SetLogLevel(4)
		utils.Logger.SetSyslog(nil)
		log.SetOutput(b)
	}
	setlog(buf)
	removelog := func() {
		utils.Logger.SetLogLevel(0)
		log.SetOutput(os.Stderr)
	}
	tmp := Cache
	defer func() {
		removelog()
		Cache = tmp
	}()
	cfg.DataDbCfg().Items = map[string]*config.ItemOpt{
		utils.CacheCDRsTBL: {
			Limit:     3,
			StaticTTL: true,
		},
	}
	Cache.Clear(nil)
	cfg.CdrsCfg().EEsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	clientConn := make(chan birpc.ClientConnector, 1)
	clientConn <- &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.EeSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {

				return utils.ErrPartiallyExecuted
			},
		},
	}
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs): clientConn,
	})
	cdrs := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}

	evs := []*utils.CGREvent{
		{ID: "TestV1ProcessEventNoTenant",
			Event: map[string]any{
				utils.CGRID:        "test1",
				utils.RunID:        utils.MetaDefault,
				utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
				utils.Destination:  "+4986517174963",
				utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
				utils.Usage:        123 * time.Minute},
		}}
	expLog := `with AttributeS`
	if _, err := cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:  true,
			chrgS:  true,
			refund: true,
			ralS:   true,
			store:  true,
			reRate: true,
			export: true,
			thdS:   true,
			stS:    true,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf.String(); !strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	removelog()
	buf2 := new(bytes.Buffer)
	setlog(buf2)
	expLog = `with ChargerS`
	if _, err := cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:  false,
			chrgS:  true,
			refund: true,
			ralS:   true,
			store:  true,
			reRate: true,
			export: true,
			thdS:   true,
			stS:    true,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf2.String(); !strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	removelog()
	buf3 := new(bytes.Buffer)
	setlog(buf3)
	Cache.Set(utils.CacheCDRIDs, utils.ConcatenatedKey("test1", utils.MetaDefault), "val", []string{}, true, utils.NonTransactional)
	expLog = `with CacheS`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:  false,
			chrgS:  false,
			refund: false,
			ralS:   true,
			store:  true,
			reRate: false,
			export: true,
			thdS:   true,
			stS:    true,
		}); err == nil || err != utils.ErrExists {
		t.Error(err)
	} else if rcvLog := buf3.String(); !strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	buf4 := new(bytes.Buffer)
	removelog()
	setlog(buf4)
	evs[0].Event[utils.AnswerTime] = "time"
	expLog = `could not retrieve previously`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:     false,
			chrgS:     false,
			refund:    true,
			ralS:      true,
			store:     true,
			reRate:    false,
			export:    true,
			thdS:      true,
			stS:       true,
			reprocess: true,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf4.String(); !strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	buf5 := new(bytes.Buffer)
	removelog()
	setlog(buf5)
	evs[0].Event[utils.AnswerTime] = time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC)
	expLog = `refunding CDR`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:     false,
			chrgS:     false,
			refund:    true,
			ralS:      false,
			store:     false,
			reRate:    false,
			export:    false,
			thdS:      false,
			stS:       false,
			reprocess: true,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf5.String(); strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	db.db.Set(utils.CacheCDRsTBL, utils.ConcatenatedKey("test1", utils.MetaDefault, "testV1CDRsRefundOutOfSessionCost"), "val", []string{}, true, utils.NonTransactional)

	buf6 := new(bytes.Buffer)
	removelog()
	setlog(buf6)
	expLog = `refunding CDR`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:     false,
			chrgS:     false,
			refund:    true,
			ralS:      false,
			store:     true,
			reRate:    false,
			export:    false,
			thdS:      false,
			stS:       false,
			reprocess: true,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf6.String(); strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	buf7 := new(bytes.Buffer)
	removelog()
	setlog(buf7)
	expLog = `exporting cdr`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:  false,
			chrgS:  false,
			refund: true,
			ralS:   false,
			store:  false,
			reRate: true,
			export: true,
			thdS:   false,
			stS:    false,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf7.String(); strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	buf8 := new(bytes.Buffer)
	removelog()
	setlog(buf8)
	expLog = `processing event`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:  false,
			chrgS:  false,
			refund: true,
			ralS:   false,
			store:  false,
			reRate: true,
			export: false,
			thdS:   true,
			stS:    false,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf8.String(); strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
	buf9 := new(bytes.Buffer)
	removelog()
	setlog(buf9)
	expLog = `processing event`
	if _, err = cdrs.processEvents(evs,
		&cdrProcessingArgs{
			attrS:  false,
			chrgS:  false,
			refund: true,
			ralS:   false,
			store:  false,
			reRate: true,
			export: false,
			thdS:   false,
			stS:    true,
		}); err == nil || err != utils.ErrPartiallyExecuted {
		t.Error(err)
	} else if rcvLog := buf9.String(); strings.Contains(rcvLog, expLog) {
		t.Errorf("expected %v,received %v", expLog, rcvLog)
	}
}

func TestV1ProcessCDR(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg: cfg,
		cdrDb:  db,
		dm:     dm,
	}
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	cd := &CDR{
		CGRID:       "cgrid1",
		RunID:       "run1",
		Category:    "category",
		Tenant:      "cgrates.org",
		RequestType: utils.PseudoPrepaid,
	}
	cdr := &CDRWithAPIOpts{
		CDR:     cd,
		APIOpts: map[string]any{},
	}
	reply := utils.StringPointer("reply")

	if err = cdrS.V1ProcessCDR(context.Background(), cdr, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{
		Result: reply,
		Error:  nil,
	}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1ProcessCDR, cdr.CGRID, cdr.RunID))

	if !has {
		t.Errorf("has no value")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}

}

func TestV1ProcessCDRSet(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg: cfg,
		cdrDb:  db,
		dm:     dm,
	}
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	cd := &CDR{
		CGRID:       "cgrid1",
		RunID:       "run1",
		Category:    "category",
		Tenant:      "cgrates.org",
		RequestType: utils.PseudoPrepaid,
	}
	cdr := &CDRWithAPIOpts{
		CDR:     cd,
		APIOpts: map[string]any{},
	}
	reply := utils.StringPointer("reply")
	Cache.Set(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1ProcessCDR, cdr.CGRID, cdr.RunID),
		&utils.CachedRPCResponse{Result: reply, Error: err},
		nil, true, utils.NonTransactional)
	if err = cdrS.V1ProcessCDR(context.Background(), cdr, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{
		Result: reply,
		Error:  nil,
	}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1ProcessCDR, cdr.CGRID, cdr.RunID))
	if !has {
		t.Errorf("has no value")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}
}

func TestV1StoreSessionCost(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	clMock := clMock(func(_ string, _, _ any) error {
		return nil
	})
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- clMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{})
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	attr := &AttrCDRSStoreSMCost{
		Cost: &SMCost{
			CGRID:    "cgrid1",
			RunID:    "run1",
			OriginID: "originid",
			CostDetails: &EventCost{
				Usage: utils.DurationPointer(1 * time.Minute),
				Cost:  utils.Float64Pointer(32.3),
			},
		},
		CheckDuplicate: false,
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	reply := utils.StringPointer("reply")
	if err = cdrS.V1StoreSessionCost(context.Background(), attr, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{
		Result: reply,
		Error:  nil,
	}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1StoreSessionCost, attr.Cost.CGRID, attr.Cost.RunID))
	if !has {
		t.Errorf("has no value")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}
	attr.Cost.CGRID = utils.EmptyString
	if err := cdrS.V1StoreSessionCost(context.Background(), attr, reply); err == nil || err.Error() != fmt.Sprintf("%s: CGRID", utils.MandatoryInfoMissing) {
		t.Error(err)
	}
}

func TestV1StoreSessionCostSet(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	clMock := clMock(func(_ string, _, _ any) error {

		return nil
	})
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- clMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{})
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	attr := &AttrCDRSStoreSMCost{
		Cost: &SMCost{
			CGRID:    "cgrid1",
			RunID:    "run1",
			OriginID: "originid",
			CostDetails: &EventCost{
				Usage: utils.DurationPointer(1 * time.Minute),
				Cost:  utils.Float64Pointer(32.3),
			},
		},
		CheckDuplicate: false,
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	reply := utils.StringPointer("reply")
	Cache.Set(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1StoreSessionCost, attr.Cost.CGRID, attr.Cost.RunID),
		&utils.CachedRPCResponse{Result: reply, Error: nil},
		nil, true, utils.NonTransactional)

	if err = cdrS.V1StoreSessionCost(context.Background(), attr, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{
		Result: reply,
		Error:  nil,
	}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1StoreSessionCost, attr.Cost.CGRID, attr.Cost.RunID))

	if !has {
		t.Errorf("has no value")
	} else if !reflect.DeepEqual(rcv, exp) {
		t.Errorf("expected %v,received %v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}
	cdrS.guard = guardian.Guardian
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 0
	attr.CheckDuplicate = true
	if err = cdrS.V1StoreSessionCost(context.Background(), attr, reply); err != nil {
		t.Error(err)
	}
}

func TestV2StoreSessionCost(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderRefundRounding: func(ctx *context.Context, args, reply any) error {
				rpl := &Account{}
				*reply.(*Account) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg): clientconn,
	})
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	args := &ArgsV2CDRSStoreSMCost{
		CheckDuplicate: false,
		Cost: &V2SMCost{
			CGRID:      "cgrid",
			RunID:      "runid",
			OriginHost: "host",
			OriginID:   "originid",
			CostSource: "cgrates",
			CostDetails: &EventCost{
				CGRID:          "evcgrid",
				RunID:          "evrunid",
				StartTime:      time.Date(2021, 11, 1, 2, 0, 0, 0, time.UTC),
				Usage:          utils.DurationPointer(122),
				Cost:           utils.Float64Pointer(134),
				Charges:        []*ChargingInterval{},
				AccountSummary: &AccountSummary{},
				Rating:         Rating{},
				Accounting:     Accounting{},
				RatingFilters:  RatingFilters{},
				Rates:          ChargedRates{},
				Timings:        ChargedTimings{},
			},
		},
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	var reply string

	if err := cdrS.V2StoreSessionCost(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{Result: utils.StringPointer("OK"), Error: nil}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1StoreSessionCost, args.Cost.CGRID, args.Cost.RunID))

	if !has {
		t.Error("has no value")
	}
	if !reflect.DeepEqual(exp, rcv) {
		t.Errorf("expected %+v,received %+v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}
	args = &ArgsV2CDRSStoreSMCost{
		Cost: &V2SMCost{},
	}
	if err = cdrS.V2StoreSessionCost(context.Background(), args, &reply); err == nil {
		t.Error(err)
	}
}

func TestV2StoreSessionCostSet(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderRefundRounding: func(ctx *context.Context, args, reply any) error {
				rpl := &Account{}
				*reply.(*Account) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg): clientconn,
	})
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	config.SetCgrConfig(cfg)
	Cache = NewCacheS(cfg, dm, nil)
	args := &ArgsV2CDRSStoreSMCost{
		CheckDuplicate: false,
		Cost: &V2SMCost{
			CGRID:      "cgrid",
			RunID:      "runid",
			OriginHost: "host",
			OriginID:   "originid",
			CostSource: "cgrates",
			CostDetails: &EventCost{
				CGRID:     "evcgrid",
				RunID:     "evrunid",
				StartTime: time.Date(2021, 11, 1, 2, 0, 0, 0, time.UTC),
				Usage:     utils.DurationPointer(122),
				Cost:      utils.Float64Pointer(134),
				Charges: []*ChargingInterval{
					{
						RatingID: "rating1",
						Increments: []*ChargingIncrement{
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id",
								CompressFactor: 5,
							},
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id",
								CompressFactor: 5,
							},
						},
						CompressFactor: 3,
						usage:          utils.DurationPointer(10 * time.Minute),
						ecUsageIdx:     utils.DurationPointer(4 * time.Minute),
						cost:           utils.Float64Pointer(38),
					},
					{
						RatingID: "rating2",
						Increments: []*ChargingIncrement{
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id",
								CompressFactor: 5,
							},
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id",
								CompressFactor: 5,
							},
						},
						CompressFactor: 3,
						usage:          utils.DurationPointer(10 * time.Minute),
						ecUsageIdx:     utils.DurationPointer(4 * time.Minute),
						cost:           utils.Float64Pointer(38),
					},
				},
				AccountSummary: &AccountSummary{
					Tenant:           "Tenant",
					ID:               "acc_id",
					BalanceSummaries: BalanceSummaries{},
					AllowNegative:    false,
					Disabled:         true,
				},
				Rating: Rating{
					"rating1": &RatingUnit{},
					"rating2": &RatingUnit{},
				},
				Accounting:    Accounting{},
				RatingFilters: RatingFilters{},
				Rates:         ChargedRates{},
				Timings:       ChargedTimings{},
			},
		},
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	reply := utils.StringPointer("reply")
	Cache.Set(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1StoreSessionCost, args.Cost.CGRID, args.Cost.RunID),
		&utils.CachedRPCResponse{Result: reply, Error: nil},
		nil, true, utils.NonTransactional)

	if err := cdrS.V2StoreSessionCost(context.Background(), args, reply); err != nil {
		t.Error(err)
	}
	exp := &utils.CachedRPCResponse{Result: reply, Error: nil}
	rcv, has := Cache.Get(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.CDRsV1StoreSessionCost, args.Cost.CGRID, args.Cost.RunID))

	if !has {
		t.Error("has no value")
	}

	if !reflect.DeepEqual(exp, rcv) {
		t.Errorf("expected %+v,received %+v", utils.ToJSON(exp), utils.ToJSON(rcv))
	}
}

func TestV1RateCDRSErr(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.ChargerSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	arg := &ArgRateCDRs{
		Flags: []string{utils.MetaStore, utils.MetaExport, utils.MetaThresholds, utils.MetaStats, utils.MetaChargers, utils.MetaAttributes},

		Tenant:  "cgrates.org",
		APIOpts: map[string]any{},
	}
	var reply string

	if err := cdrS.V1RateCDRs(context.Background(), arg, &reply); err == nil || err != utils.ErrNotFound {
		t.Error(err)
	}
}

func TestV1GetCDRsErr(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	defer func() {
		config.SetCgrConfig(config.NewDefaultCGRConfig())
	}()
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	idb, err := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Fatal(err)
	}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: nil,
		cdrDb:   idb,
		dm:      dm,
	}
	args := utils.RPCCDRsFilterWithAPIOpts{

		RPCCDRsFilter: &utils.RPCCDRsFilter{
			CGRIDs:         []string{"CGRIDs"},
			NotCGRIDs:      []string{"NotCGRIDs"},
			OriginHosts:    []string{"OriginHosts"},
			SetupTimeStart: "time",
			SetupTimeEnd:   "2020-04-18T11:46:26.371Z",
		},
		Tenant:  "cgrates.org",
		APIOpts: map[string]any{},
	}
	var cdrs *[]*CDR
	if err := cdrS.V1GetCDRs(context.Background(), args, cdrs); err == nil {
		t.Error(utils.NewErrServerError(utils.ErrNotFound))
	}
	args.RPCCDRsFilter.SetupTimeStart = ""
	if err := cdrS.V1GetCDRs(context.Background(), args, cdrs); err == nil || err.Error() != fmt.Sprintf("SERVER_ERROR: %s", utils.ErrNotFound) {
		t.Error(utils.NewErrServerError(utils.ErrNotFound))
	}
}
func TestGetCostFromRater2(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	cfg.CdrsCfg().SchedulerConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.SchedulerConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderDebit: func(ctx *context.Context, args, reply any) error {

				return utils.ErrAccountNotFound
			},
			utils.SchedulerSv1ExecuteActionPlans: func(ctx *context.Context, args, reply any) error {
				rpl := "reply"
				*reply.(*string) = rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg):     clientconn,
		utils.ConcatenatedKey(utils.MetaInternal, utils.SchedulerConnsCfg): clientconn,
	})
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	cdr := &CDRWithAPIOpts{

		CDR: &CDR{
			ToR:         "tor",
			Tenant:      "tenant",
			Category:    "cdr",
			Subject:     "cdrsubj",
			Account:     "acc_cdr",
			Destination: "acc_dest",
			RequestType: utils.MetaDynaprepaid,
			Usage:       1 * time.Minute,
		},
		APIOpts: map[string]any{},
	}

	if _, err := cdrS.getCostFromRater(cdr); err == nil || err != utils.ErrAccountNotFound {
		t.Error(err)
	}
}

func TestGetCostFromRater3(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	ccMock := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderGetCost: func(ctx *context.Context, args, reply any) error {

				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMock
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg): clientconn,
	})
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	cdr := &CDRWithAPIOpts{

		CDR: &CDR{
			ToR:         "tor",
			Tenant:      "tenant",
			Category:    "cdr",
			Subject:     "cdrsubj",
			Account:     "acc_cdr",
			Destination: "acc_dest",
			RequestType: "default",
			Usage:       1 * time.Minute,
		},
		APIOpts: map[string]any{},
	}

	if _, err := cdrS.getCostFromRater(cdr); err == nil || err != rpcclient.ErrUnsupporteServiceMethod {
		t.Errorf("expected %+v,received %v", rpcclient.ErrUnsupporteServiceMethod, err)
	}
}

func TestV2StoreSessionCost2(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 0
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	ccMOck := &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderRefundRounding: func(ctx *context.Context, args, reply any) error {
				rpl := &Account{}
				*reply.(*Account) = *rpl
				return nil
			},
		},
	}
	clientconn := make(chan birpc.ClientConnector, 1)
	clientconn <- ccMOck
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg): clientconn,
	})
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}

	args := &ArgsV2CDRSStoreSMCost{

		CheckDuplicate: false,
		Cost: &V2SMCost{
			CGRID:      "cgrid",
			RunID:      "runid",
			OriginHost: "host",
			OriginID:   "originid",
			CostSource: "cgrates",
			CostDetails: &EventCost{
				CGRID:     "evcgrid",
				RunID:     "evrunid",
				StartTime: time.Date(2021, 11, 1, 2, 0, 0, 0, time.UTC),
				Usage:     utils.DurationPointer(122),
				Cost:      utils.Float64Pointer(134),
				Charges: []*ChargingInterval{
					{

						RatingID: utils.MetaRounding,
						Increments: []*ChargingIncrement{
							{

								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id",
								CompressFactor: 5,
							},
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id2",
								CompressFactor: 5,
							},
						},
						CompressFactor: 3,
						usage:          utils.DurationPointer(10 * time.Minute),
						ecUsageIdx:     utils.DurationPointer(4 * time.Minute),
						cost:           utils.Float64Pointer(38),
					},
					{
						RatingID: utils.MetaRounding,

						Increments: []*ChargingIncrement{
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id",
								CompressFactor: 5,
							},
							{
								Usage:          5 * time.Minute,
								Cost:           23,
								AccountingID:   "acc_id2",
								CompressFactor: 5,
							},
						},
						CompressFactor: 3,
						usage:          utils.DurationPointer(10 * time.Minute),
						ecUsageIdx:     utils.DurationPointer(4 * time.Minute),
						cost:           utils.Float64Pointer(38),
					},
				},
				AccountSummary: &AccountSummary{
					Tenant:           "Tenant",
					ID:               "acc_id",
					BalanceSummaries: BalanceSummaries{},
					AllowNegative:    false,
					Disabled:         true,
				},

				Accounting: Accounting{
					"acc_id": &BalanceCharge{
						RatingID: utils.MetaRounding,
					},
					"acc_id2": &BalanceCharge{
						RatingID: utils.MetaRounding,
					},
				},
				RatingFilters: RatingFilters{
					"filtersid": RatingMatchedFilters{
						utils.Subject:               "string",
						utils.DestinationPrefixName: "string",
						utils.DestinationID:         "dest",
						utils.RatingPlanID:          "rating",
					},
					"ratefilter": RatingMatchedFilters{
						utils.Subject:               "string",
						utils.DestinationPrefixName: "string",
						utils.DestinationID:         "dest",
						utils.RatingPlanID:          "rating",
					},
				},
				Rates:   ChargedRates{},
				Timings: ChargedTimings{},
				Rating: Rating{
					utils.MetaRounding: &RatingUnit{
						ConnectFee:       21,
						RoundingMethod:   "method",
						RoundingDecimals: 3,
						MaxCost:          22,
						MaxCostStrategy:  "sr",
						RatesID:          "rates",
						RatingFiltersID:  "filtersid",
					},
				},
			},
		},
		Tenant:  "cgrates.org",
		APIOpts: map[string]any{},
	}
	var reply string
	if err := cdrS.V2StoreSessionCost(context.Background(), args, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Errorf("expected %+v,received %+v", utils.OK, reply)
	}
	clientconn2 := make(chan birpc.ClientConnector, 1)
	clientconn2 <- &ccMock{

		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderRefundRounding: func(ctx *context.Context, args, reply any) error {
				rpl := &Account{}
				*reply.(*Account) = *rpl
				return utils.ErrNotFound
			},
		},
	}
	cdrS.connMgr.rpcInternal[utils.ConcatenatedKey(utils.MetaInternal, utils.RateSConnsCfg)] = clientconn2

	if err := cdrS.V2StoreSessionCost(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}

}
func TestV1RateCDRSSuccesful(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.ChargerSConnsCfg)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	cdr := &CDR{
		CGRID:       "Cdr1",
		OrderID:     123,
		ToR:         utils.MetaVoice,
		OriginID:    "OriginCDR1",
		OriginHost:  "192.168.1.1",
		Source:      "test",
		RequestType: utils.MetaRated,
		Category:    "call",
		Account:     "1001",
		Subject:     "1001",
		Destination: "+4986517174963",
		RunID:       utils.MetaDefault,
		Usage:       time.Duration(0),
		ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
		Cost:        1.01,
	}
	if err := cdrS.cdrDb.SetCDR(cdr, true); err != nil {
		t.Error(err)
	}
	arg := &ArgRateCDRs{
		Flags: []string{utils.MetaStore, utils.MetaExport, utils.MetaThresholds, utils.MetaStats, utils.MetaChargers, utils.MetaAttributes},
		RPCCDRsFilter: utils.RPCCDRsFilter{
			CGRIDs: []string{"Cdr1"},
		},
		Tenant:  "cgrates.org",
		APIOpts: map[string]any{},
	}
	var reply *string

	if err := cdrS.V1RateCDRs(context.Background(), arg, reply); err == nil {
		t.Error(err)
	}
}

func TestCdrServerStoreSMCost(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.ChargerSConnsCfg)}
	db, err := NewInternalDB(nil, nil, true, nil, map[string]*config.ItemOpt{
		utils.CacheSessionCostsTBL: {
			Limit:     2,
			TTL:       2 * time.Minute,
			StaticTTL: true,
			Remote:    false,
			Replicate: true,
		},
	})
	if err != nil {
		t.Error(err)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)

	smCost := &SMCost{
		CGRID:      "cgrid",
		RunID:      "runid",
		OriginHost: "originhost",
		OriginID:   "origin",
		CostSource: "cost",
		Usage:      1 * time.Minute,
		CostDetails: &EventCost{
			CGRID:          "ecId",
			RunID:          "ecRunId",
			StartTime:      time.Date(2022, 12, 1, 12, 0, 0, 0, time.UTC),
			Usage:          utils.DurationPointer(1 * time.Hour),
			Cost:           utils.Float64Pointer(12.1),
			Charges:        []*ChargingInterval{},
			AccountSummary: &AccountSummary{},
			Accounting:     Accounting{},
			RatingFilters:  RatingFilters{},
			Rates:          ChargedRates{},
		},
	}
	guardian := guardian.GuardianLocker{}
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
		guard:   &guardian,
	}
	if err := cdrS.cdrDb.SetSMCost(smCost); err != nil {
		t.Error(err)
	}

}

func TestCdrSRateCDR(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	tmp := Cache
	defer func() {
		config.SetCgrConfig(config.NewDefaultCGRConfig())
		Cache = tmp
	}()
	Cache.Clear(nil)
	cfg.CdrsCfg().SMCostRetries = 1
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.ChargerSConnsCfg)}
	cfg.CdrsCfg().RaterConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	db, err := NewInternalDB(nil, nil, true, nil, map[string]*config.ItemOpt{
		utils.CacheSessionCostsTBL: {
			Limit:     2,
			TTL:       2 * time.Minute,
			StaticTTL: true,
			Remote:    false,
			Replicate: true,
		},
	})
	if err != nil {
		t.Error(err)
	}
	clientConn := make(chan birpc.ClientConnector, 1)
	clientConn <- &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ResponderDebit: func(ctx *context.Context, args, reply any) error {
				cc := &CallCost{
					Category:    "generic",
					Tenant:      "cgrates.org",
					Subject:     "1001",
					Account:     "1001",
					Destination: "data",
					ToR:         "*data",
					Cost:        0,
				}
				*reply.(*CallCost) = *cc
				return nil
			},
		},
	}
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): clientConn,
	})
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	smc := &SMCost{
		CGRID:       "cgrid",
		RunID:       "runid",
		OriginHost:  "originHost",
		OriginID:    "originID",
		CostSource:  "cost_source",
		Usage:       2 * time.Minute,
		CostDetails: &EventCost{},
	}
	if err := cdrS.cdrDb.SetSMCost(smc); err != nil {
		t.Error(err)
	}
	db.db.Set(utils.CacheSessionCostsTBL, "cgrates:item1", &SMCost{
		CGRID:      "CGRID",
		RunID:      utils.MetaDefault,
		OriginHost: utils.FreeSWITCHAgent,
		OriginID:   "Origin1",
		Usage:      time.Second,
		CostSource: utils.MetaSessionS,
	}, []string{utils.ConcatenatedKey(utils.CGRID, "CGRID_22"),
		utils.ConcatenatedKey(utils.RunID, "RUN_ID1"),
		utils.ConcatenatedKey(utils.OriginHost, "ORG_Host1")}, true, utils.NonTransactional)
	cdrOpts := &CDRWithAPIOpts{
		CDR: &CDR{
			CGRID:       "CGRID_22",
			RunID:       "RUN_ID1",
			OriginHost:  "ORG_Host1",
			OrderID:     222,
			Usage:       4 * time.Second,
			RequestType: utils.Prepaid,
			ExtraFields: map[string]string{
				utils.LastUsed: "extra",
			},
		},
	}

	if _, err := cdrS.rateCDR(cdrOpts); err != nil {
		t.Error(err)
	}

	cdrOpts.ExtraFields = map[string]string{}
	cdrOpts.Usage = 0
	if _, err := cdrS.rateCDR(cdrOpts); err != nil {
		t.Error(err)
	}

	cdrOpts.CostDetails = &EventCost{
		CGRID:     "7636f3f1a06dffa038ba7900fb57f52d28830a24",
		RunID:     utils.MetaDefault,
		StartTime: time.Date(2018, 7, 27, 0, 59, 21, 0, time.UTC),
		Usage:     utils.DurationPointer(2 * time.Second),
		Charges: []*ChargingInterval{
			{
				RatingID: "cc68da4",
				Increments: []*ChargingIncrement{
					{
						Usage:          102400,
						AccountingID:   "0d87a64",
						CompressFactor: 103,
					},
				},
				CompressFactor: 1,
			},
		},
		AccountSummary: &AccountSummary{
			Tenant: "cgrates.org",
			ID:     "dan",
			BalanceSummaries: []*BalanceSummary{
				{
					UUID:  "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
					ID:    "addon_data",
					Type:  utils.MetaData,
					Value: 10726871040},
			},
		},
	}
	if _, err := cdrS.rateCDR(cdrOpts); err != nil {
		t.Error(err)
	}
}

func TestChrgrSProcessEvent(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	clienConn := make(chan birpc.ClientConnector, 1)
	clienConn <- &ccMock{
		calls: map[string]func(ctx *context.Context, args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
				*reply.(*[]*ChrgSProcessEventReply) = []*ChrgSProcessEventReply{
					{
						ChargerSProfile:    "Charger1",
						AttributeSProfiles: []string{"cgrates.org:ATTR_1001_SIMPLEAUTH"},
						AlteredFields:      []string{utils.MetaReqRunID, "*req.Password"},
						CGREvent: &utils.CGREvent{ // matching Charger1
							Tenant: "cgrates.org",
							ID:     "event1",
							Event: map[string]any{
								utils.AccountField: "1001",
								"Password":         "CGRateS.org",
								"RunID":            utils.MetaDefault,
							},
							APIOpts: map[string]any{
								utils.OptsContext:              "simpleauth",
								utils.MetaSubsys:               utils.MetaChargers,
								utils.OptsAttributesProfileIDs: []string{"ATTR_1001_SIMPLEAUTH"},
							},
						},
					},
				}
				return nil
			},
		},
	}
	connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): clienConn,
	})
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: connMgr,
	}
	cgrEv := utils.CGREvent{
		ID: "TestV1ProcessEventNoTenant",
		Event: map[string]any{
			utils.CGRID:        "test1",
			utils.RunID:        utils.MetaDefault,
			utils.OriginID:     "testV1CDRsRefundOutOfSessionCost",
			utils.RequestType:  utils.MetaPrepaid,
			utils.AccountField: "testV1CDRsRefundOutOfSessionCost",
			utils.Destination:  "+4986517174963",
			utils.AnswerTime:   time.Date(2019, 11, 27, 12, 21, 26, 0, time.UTC),
			utils.Usage:        123 * time.Minute,
		},
	}
	expcgrEv := []*utils.CGREvent{
		{
			Tenant: "cgrates.org",
			ID:     "event1",
			Event: map[string]any{
				utils.AccountField: "1001",
				"Password":         "CGRateS.org",
				"RunID":            utils.MetaDefault,
			},
			APIOpts: map[string]any{
				utils.OptsContext:              "simpleauth",
				utils.MetaSubsys:               utils.MetaChargers,
				utils.OptsAttributesProfileIDs: []string{"ATTR_1001_SIMPLEAUTH"},
			},
		},
	}
	if val, err := cdrS.chrgrSProcessEvent(&cgrEv); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(val, expcgrEv) {
		t.Errorf("expected %v,received %v", utils.ToJSON(expcgrEv), utils.ToJSON(val))
	}
}

func TestCDRServerListenAndServe(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	tmpConnMgr := connMgr
	defer func() {
		connMgr = tmpConnMgr
		config.SetCgrConfig(config.NewDefaultCGRConfig())
	}()
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMgr,
		dm:      dm,
		cdrDb:   db,
	}
	stopChan := make(chan struct{}, 1)
	go func() {
		time.Sleep(10 * time.Millisecond)
		stopChan <- struct{}{}
	}()
	cdrS.ListenAndServe(stopChan)
}

func TestCDRServerListenAndServe2(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	tmpConnMgr := connMgr
	defer func() {
		connMgr = tmpConnMgr
		config.SetCgrConfig(config.NewDefaultCGRConfig())
	}()
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMgr,
		dm:      dm,
		cdrDb:   db,
	}
	stopChan := make(chan struct{}, 1)
	go func() {
		time.Sleep(40 * time.Millisecond)
		stopChan <- struct{}{}
	}()

	go func() {
		time.Sleep(10 * time.Millisecond)
		cdrS.storDBChan <- db
	}()
	cdrS.ListenAndServe(stopChan)
}

func TestStoreSMCostErr(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	tmpConnMgr := connMgr
	tmpCache := Cache
	defer func() {
		connMgr = tmpConnMgr
		config.SetCgrConfig(config.NewDefaultCGRConfig())
		Cache = tmpCache
	}()
	Cache.Clear(nil)
	cfg.DataDbCfg().Items = map[string]*config.ItemOpt{
		utils.CacheSessionCostsTBL: {
			Replicate: true,
		},
	}
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	db.db.Set(utils.CacheSessionCostsTBL, "CGRID:CGRID", nil, []string{"GRP_1"}, true, utils.NonTransactional)
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		connMgr: connMgr,
		dm:      dm,
		cdrDb:   db,
		guard:   guardian.Guardian,
	}
	smCost := &SMCost{
		CGRID:      "CGRID",
		RunID:      utils.MetaDefault,
		OriginHost: utils.FreeSWITCHAgent,
		OriginID:   "Origin1",
		Usage:      time.Second,
		CostSource: utils.MetaSessionS,
		CostDetails: &EventCost{
			CGRID:     "164b0422fdc6a5117031b427439482c6a4f90e41",
			RunID:     utils.MetaDefault,
			StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
			Charges: []*ChargingInterval{
				{
					RatingID: "c1a5ab9",
					Increments: []*ChargingIncrement{
						{
							Usage:          0,
							Cost:           0.1,
							AccountingID:   "9bdad10",
							CompressFactor: 1,
						},
					},
					CompressFactor: 1,
				},
			},
			AccountSummary: &AccountSummary{
				Tenant: "cgrates.org",
				ID:     "dan",
				BalanceSummaries: []*BalanceSummary{
					{
						UUID:  "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
						Type:  utils.MetaMonetary,
						Value: 50,
					},
				},
				AllowNegative: false,
				Disabled:      false,
			},
			Rating: Rating{
				"3cd6425": &RatingUnit{
					RoundingMethod:   "*up",
					RoundingDecimals: 5,
					TimingID:         "7f324ab",
					RatesID:          "4910ecf",
					RatingFiltersID:  "43e77dc",
				},
			},
			Accounting: Accounting{
				"a012888": &BalanceCharge{
					AccountID:   "cgrates.org:dan",
					BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
					Units:       0.01,
				},
			},
			RatingFilters: RatingFilters{
				"43e77dc": RatingMatchedFilters{
					"DestinationID":     "GERMANY",
					"DestinationPrefix": "+49",
					"RatingPlanID":      "RPL_RETAIL1",
					"Subject":           "*out:cgrates.org:call:*any",
				},
			},
			Rates: ChargedRates{
				"ec1a177": RateGroups{
					&RGRate{
						GroupIntervalStart: 0,
						Value:              0.01,
						RateIncrement:      time.Minute,
						RateUnit:           time.Second},
				},
			},
			Timings: ChargedTimings{
				"7f324ab": &ChargedTiming{
					StartTime: "00:00:00",
				}}}}

	if err := cdrS.storeSMCost(smCost, true); err != nil {
		t.Error(err)
	}
}

func TestCDRSGetCDRs(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	cfg.CdrsCfg().EEsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs)}
	cfg.CdrsCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	cfg.CdrsCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)}
	cfg.CdrsCfg().SMCostRetries = 1
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	clientConn := make(chan birpc.ClientConnector, 1)
	clientConn <- clMock(func(serviceMethod string, _, _ any) error {
		if serviceMethod == utils.EeSv1ProcessEvent {

			return nil
		}
		if serviceMethod == utils.ThresholdSv1ProcessEvent {
			return nil
		}
		if serviceMethod == utils.StatSv1ProcessEvent {
			return nil
		}

		return utils.ErrNotImplemented
	})
	cdrS := &CDRServer{
		cgrCfg: cfg,
		cdrDb:  db,
		dm:     dm,
		connMgr: NewConnManager(cfg, map[string]chan birpc.ClientConnector{
			utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs):        clientConn,
			utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): clientConn,
			utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats):      clientConn,
		}),
	}
	arg := &ArgV1ProcessEvent{
		CGREvent: utils.CGREvent{
			Tenant: "cgrates.org",
			ID:     "Event1",
			Event: map[string]any{
				utils.Tenant:       "cgrates.org",
				utils.ToR:          utils.MetaVoice,
				utils.OriginHost:   "host",
				utils.RequestType:  utils.MetaPrepaid,
				utils.AccountField: "1001",
				utils.OriginID:     "OriginCDR2",
				utils.CGRID:        "TestCGRID",
				utils.Subject:      "1001",
				utils.RunID:        utils.MetaDefault,
				utils.Destination:  "1002",
				utils.SetupTime:    time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC),
				utils.AnswerTime:   time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC),
				utils.Usage:        10 * time.Minute,
			},
			APIOpts: map[string]any{
				utils.OptsStatS: true,
			},
		},
		Flags: []string{
			utils.MetaStore, utils.MetaRALs, utils.MetaExport, utils.MetaThresholds,
		},
	}
	var reply string
	if err := cdrS.V1ProcessEvent(context.Background(), arg, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Error("Expected OK")
	}

	var cdrs []*CDR
	args := utils.RPCCDRsFilterWithAPIOpts{
		RPCCDRsFilter: &utils.RPCCDRsFilter{RequestTypes: []string{utils.MetaPrepaid}},
	}
	if err := cdrS.V1GetCDRs(context.Background(), args, &cdrs); err != nil {
		t.Error(err)
	}
}

func TestV1RateCDRsSuccesful(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	db, dErr := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if dErr != nil {
		t.Error(dErr)
	}
	dm := NewDataManager(db, cfg.CacheCfg(), nil)
	cdrS := &CDRServer{
		cgrCfg:  cfg,
		cdrDb:   db,
		dm:      dm,
		connMgr: nil,
	}
	cdr := &CDR{
		CGRID:       utils.Sha1("dsafdsaf", time.Date(2023, 11, 7, 8, 42, 26, 0, time.UTC).String()),
		OrderID:     123,
		ToR:         utils.MetaVoice,
		OriginID:    "dsafdsaf",
		OriginHost:  "192.168.1.1",
		Source:      utils.UnitTest,
		RequestType: utils.MetaRated,
		Tenant:      "cgrates.org",
		Category:    "call",
		Account:     "1001",
		Subject:     "1002",
		Destination: "+4986517174963",
		SetupTime:   time.Date(2023, 11, 7, 8, 42, 20, 0, time.UTC),
		AnswerTime:  time.Date(2023, 11, 7, 8, 42, 26, 0, time.UTC),
		RunID:       utils.MetaDefault,
		Usage:       10 * time.Second,
		Cost:        1.01,
	}
	if err := db.SetCDR(cdr, true); err != nil {
		t.Error(err)
	}
	var reply string
	arg := &ArgRateCDRs{
		Flags:  []string{utils.MetaRerate},
		Tenant: "cgrates.org",
		RPCCDRsFilter: utils.RPCCDRsFilter{
			Accounts: []string{"1001"},
		},
		APIOpts: map[string]any{},
	}
	if err := cdrS.V1RateCDRs(context.Background(), arg, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Error("Expected reply to be ok")
	}
}

func TestCdrsSetCloneable(t *testing.T) {
	tests := []struct {
		input    bool
		expected bool
	}{
		{input: true, expected: true},
		{input: false, expected: false},
	}
	for _, tt := range tests {
		attr := &ArgV1ProcessEvents{
			Flags:     []string{},
			CGREvents: []*utils.CGREvent{},
			APIOpts:   make(map[string]any),
			clnb:      !tt.input,
		}
		attr.SetCloneable(tt.input)
		if attr.clnb != tt.expected {
			t.Errorf("SetCloneable(%v) = %v; expected %v", tt.input, attr.clnb, tt.expected)
		}
	}
}

func TestCdrsSetCloneableEvent(t *testing.T) {
	arg := &ArgV1ProcessEvent{}
	arg.SetCloneable(true)
	if !arg.clnb {
		t.Errorf("expected clnb to be true, got false")
	}
	arg.SetCloneable(false)

	if arg.clnb {
		t.Errorf("expected clnb to be false, got true")
	}
}

func TestCdrsRPCClone(t *testing.T) {

	arg := &ArgV1ProcessEvent{}

	cloned1, err1 := arg.RPCClone()

	if err1 != nil {
		t.Errorf("unexpected error: %v", err1)
	}
	if cloned1 != arg {
		t.Errorf("expected cloned object to be identical, got different objects")
	}
	arg.SetCloneable(true)
	cloned2, err2 := arg.RPCClone()
	if err2 != nil {
		t.Errorf("unexpected error: %v", err2)
	}
	if cloned2 == arg {
		t.Errorf("expected cloned object to be different, got identical objects")
	}
}

func TestCdrsRPCCloneArgs(t *testing.T) {
	arg := &ArgV1ProcessEvents{}

	cloned1, err1 := arg.RPCClone()
	if err1 != nil {
		t.Errorf("unexpected error: %v", err1)
	}
	if cloned1 != arg {
		t.Errorf("expected cloned object to be same, got different")
	}
	arg.SetCloneable(true)
	cloned2, err2 := arg.RPCClone()
	if err2 != nil {
		t.Errorf("unexpected error: %v", err2)
	}
	if cloned2 == arg {
		t.Errorf("expected cloned object to be different, got same")
	}
}

func TestNewMapEventFromReqForm(t *testing.T) {
	form := url.Values{}
	form.Add("key1", "value1")
	form.Add("key2", "value2")

	req, err := http.NewRequest("POST", "http://cgrates.com", nil)
	if err != nil {
		t.Fatalf("failed to create request: %v", err)
	}
	req.Form = form
	mp, err := newMapEventFromReqForm(req)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	expectedRemoteAddr := req.RemoteAddr
	if mp[utils.Source] != expectedRemoteAddr {
		t.Errorf("expected mp[%q] to be %q, got %q", utils.Source, expectedRemoteAddr, mp[utils.Source])
	}
	if mp["key1"] != "value1" {
		t.Errorf("expected mp[%q] to be %q, got %q", "key1", "value1", mp["key1"])
	}
	if mp["key2"] != "value2" {
		t.Errorf("expected mp[%q] to be %q, got %q", "key2", "value2", mp["key2"])
	}
}

func TestCDRSV1ProcessEvents(t *testing.T) {

	ctx := context.Background()
	cfg := config.NewDefaultCGRConfig()
	cdrS := &CDRServer{
		cgrCfg: cfg,
	}
	arg := &ArgV1ProcessEvents{
		Flags:     []string{},
		CGREvents: []*utils.CGREvent{},
		APIOpts:   make(map[string]any),
	}
	expectedReply := utils.OK
	var reply string
	err := cdrS.V1ProcessEvents(ctx, arg, &reply)

	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}
	if reply != expectedReply {
		t.Errorf("Expected reply %q, got %q", expectedReply, reply)
	}
}

func TestNewMapEventFromReqForm_ParseForm(t *testing.T) {
	formData := url.Values{}
	formData.Add("key", "value")
	req := httptest.NewRequest("POST", "/", strings.NewReader(formData.Encode()))
	req.Header.Add("Content-Type", "application/x-www-cgrates-urlencoded")
	_, err := newMapEventFromReqForm(req)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
}

func TestArgV1ProcessEventsClone(t *testing.T) {
	original := &ArgV1ProcessEvents{
		Flags: []string{"flag1", "flag2"},
		CGREvents: []*utils.CGREvent{
			{
				ID:      "event1",
				Tenant:  "cgrates.org",
				Time:    utils.TimePointer(time.Now()),
				Event:   map[string]any{"key": "value"},
				APIOpts: map[string]any{"opt1": "val1"},
			},
			{
				ID:      "event2",
				Tenant:  "cgrates.org2",
				Time:    utils.TimePointer(time.Now().Add(1 * time.Hour)),
				Event:   map[string]any{"key2": "value2"},
				APIOpts: map[string]any{"opt2": "val2"},
			},
		},
		APIOpts: map[string]any{"apiOpt1": "optValue"},
	}

	cloned := original.Clone()

	if cloned == original {
		t.Errorf("Expected a new cloned object, but the cloned object is the same as the original.")
	}

	if len(cloned.Flags) != len(original.Flags) {
		t.Errorf("Expected Flags length to be %d, got %d", len(original.Flags), len(cloned.Flags))
	} else {
		for i := range original.Flags {
			if original.Flags[i] != cloned.Flags[i] {
				t.Errorf("Expected Flags[%d] to be '%s', got '%s'", i, original.Flags[i], cloned.Flags[i])
			}
		}
	}

	if len(cloned.CGREvents) != len(original.CGREvents) {
		t.Errorf("Expected CGEvents length to be %d, got %d", len(original.CGREvents), len(cloned.CGREvents))
	} else {
		for i, originalEvent := range original.CGREvents {
			clonedEvent := cloned.CGREvents[i]
			if originalEvent == clonedEvent {
				t.Errorf("Expected CGEvent[%d] to be a clone, but they are the same instance.", i)
			}
			if originalEvent.ID != clonedEvent.ID || originalEvent.Tenant != clonedEvent.Tenant {
				t.Errorf("Expected CGEvent[%d] to have the same values, but got ID: %s and Tenant: %s in the clone", i, clonedEvent.ID, clonedEvent.Tenant)
			}
		}
	}

	if len(cloned.APIOpts) != len(original.APIOpts) {
		t.Errorf("Expected APIOpts length to be %d, got %d", len(original.APIOpts), len(cloned.APIOpts))
	} else {
		for key, value := range original.APIOpts {
			if cloned.APIOpts[key] != value {
				t.Errorf("Expected APIOpts[%s] to be '%v', got '%v'", key, value, cloned.APIOpts[key])
			}
		}
	}

	original.Flags[0] = "modifiedFlag"
	original.CGREvents[0].ID = "modifiedEvent"
	original.APIOpts["apiOpt1"] = "modifiedValue"

	if cloned.Flags[0] == "modifiedFlag" {
		t.Errorf("Expected cloned Flags to be unaffected, but it was modified.")
	}
	if cloned.CGREvents[0].ID == "modifiedEvent" {
		t.Errorf("Expected cloned CGEvents to be unaffected, but it was modified.")
	}
	if cloned.APIOpts["apiOpt1"] == "modifiedValue" {
		t.Errorf("Expected cloned APIOpts to be unaffected, but it was modified.")
	}
}

func TestNewCDRProcessingArgsNoCfg(t *testing.T) {
	t.Run("EmptyFlagsAndOpts", func(t *testing.T) {
		flags := utils.FlagsWithParams{}
		opts := map[string]any{}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}
		if args == nil {
			t.Fatal("Expected non-nil args")
		}

		expected := &cdrProcessingArgs{}
		if *args != *expected {
			t.Errorf("Expected %+v, got %+v", expected, args)
		}
	})

	t.Run("OptsOnly", func(t *testing.T) {
		flags := utils.FlagsWithParams{}
		opts := map[string]any{
			utils.OptsAttributeS: true,
			utils.OptsChargerS:   true,
			utils.OptsThresholdS: true,
			utils.OptsStatS:      true,
			utils.OptsRerate:     true,
			utils.OptsRefund:     false,
			utils.OptsRALs:       false,
		}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}

		if !args.attrS {
			t.Error("Expected attrS to be true")
		}
		if !args.chrgS {
			t.Error("Expected chrgS to be true")
		}
		if !args.thdS {
			t.Error("Expected thdS to be true")
		}
		if !args.stS {
			t.Error("Expected stS to be true")
		}
		if !args.reRate {
			t.Error("Expected reRate to be true")
		}
		if args.ralS {
			t.Error("Expected ralS to be false ")
		}
		if args.refund {
			t.Error("Expected refund to be false ")
		}
		if args.reprocess {
			t.Error("Expected reprocess to be false ")
		}
	})

	t.Run("FlagsOnly", func(t *testing.T) {
		flags := utils.FlagsWithParams{
			utils.MetaAttributes: utils.FlagParams{"true": []string{}},
			utils.MetaChargers:   utils.FlagParams{"true": []string{}},
			utils.MetaStore:      utils.FlagParams{"true": []string{}},
			utils.MetaExport:     utils.FlagParams{"true": []string{}},
			utils.MetaThresholds: utils.FlagParams{"true": []string{}},
			utils.MetaStats:      utils.FlagParams{"true": []string{}},
			utils.MetaRerate:     utils.FlagParams{"false": []string{}},
			utils.MetaRefund:     utils.FlagParams{"true": []string{}},
			utils.MetaReprocess:  utils.FlagParams{"false": []string{}},
			utils.MetaRALs:       utils.FlagParams{"true": []string{}},
		}
		opts := map[string]any{}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}

		if !args.attrS {
			t.Error("Expected attrS to be true")
		}
		if !args.chrgS {
			t.Error("Expected chrgS to be true")
		}
		if !args.store {
			t.Error("Expected store to be true")
		}
		if !args.export {
			t.Error("Expected export to be true")
		}
		if !args.thdS {
			t.Error("Expected thdS to be true")
		}
		if !args.stS {
			t.Error("Expected stS to be true")
		}
		if args.reRate {
			t.Error("Expected reRate to be false")
		}
		if !args.refund {
			t.Error("Expected refund to be true")
		}
		if args.reprocess {
			t.Error("Expected reprocess to be false (overridden by flag)")
		}
		if !args.ralS {
			t.Error("Expected ralS to be true")
		}
	})

	t.Run("FlagsOverrideOpts", func(t *testing.T) {
		flags := utils.FlagsWithParams{
			utils.MetaAttributes: utils.FlagParams{"false": []string{}},
			utils.MetaChargers:   utils.FlagParams{"true": []string{}},
		}
		opts := map[string]any{
			utils.OptsAttributeS: true,
			utils.OptsChargerS:   false,
		}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}

		if args.attrS {
			t.Error("Expected attrS to be false (flag overrides option)")
		}
		if !args.chrgS {
			t.Error("Expected chrgS to be true (flag overrides option)")
		}
	})

	t.Run("ReRateLogicTrue", func(t *testing.T) {
		flags := utils.FlagsWithParams{}
		opts := map[string]any{
			utils.OptsRerate: true,
		}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}

		if !args.reRate {
			t.Error("Expected reRate to be true")
		}
		if !args.ralS {
			t.Error("Expected ralS to be true (auto-set by reRate)")
		}
		if !args.refund {
			t.Error("Expected refund to be true (auto-set by reRate)")
		}
		if !args.reprocess {
			t.Error("Expected reprocess to be true (auto-set by refund)")
		}
	})

	t.Run("RefundLogicWithoutReRate", func(t *testing.T) {
		flags := utils.FlagsWithParams{}
		opts := map[string]any{
			utils.OptsRefund: true,
			utils.OptsRerate: false,
		}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}

		if args.reRate {
			t.Error("Expected reRate to be false")
		}
		if !args.refund {
			t.Error("Expected refund to be true")
		}
		if args.ralS {
			t.Error("Expected ralS to be false (refund without reRate)")
		}
		if !args.reprocess {
			t.Error("Expected reprocess to be true (auto-set by refund)")
		}
	})

	t.Run("ErrorHandling", func(t *testing.T) {
		flags := utils.FlagsWithParams{}

		opts := map[string]any{
			utils.OptsAttributeS: make(chan int),
		}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err == nil {
			t.Error("Expected error for invalid option type")
		}
		if args != nil {
			t.Error("Expected nil args when error occurs")
		}

		opts = map[string]any{
			utils.OptsChargerS: []int{1, 2, 3},
		}

		args, err = newCDRProcessingArgsNoCfg(flags, opts)

		if err == nil {
			t.Error("Expected error for invalid option type")
		}
		if args != nil {
			t.Error("Expected nil args when error occurs")
		}
	})

	t.Run("StringAndNumericOpts", func(t *testing.T) {
		flags := utils.FlagsWithParams{}
		opts := map[string]any{
			utils.OptsAttributeS: "true",
			utils.OptsChargerS:   "false",
			utils.OptsThresholdS: 1,
			utils.OptsStatS:      0,
			utils.OptsRerate:     1.5,
			utils.OptsRALs:       0.0,
		}

		args, err := newCDRProcessingArgsNoCfg(flags, opts)

		if err != nil {
			t.Errorf("Expected no error, got: %v", err)
		}

		if !args.attrS {
			t.Error("Expected attrS to be true (string 'true')")
		}
		if args.chrgS {
			t.Error("Expected chrgS to be false (string 'false')")
		}
		if !args.thdS {
			t.Error("Expected thdS to be true (int 1)")
		}
		if args.stS {
			t.Error("Expected stS to be false (int 0)")
		}
		if !args.reRate {
			t.Error("Expected reRate to be true (float64 1.5)")
		}

	})

}
