/*
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 (
	"reflect"
	"testing"

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

func TestFilterIndexesCheckingDynamicPathToNotIndex(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	db, _ := NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
	dbCM := NewDBConnManager(map[string]DataDB{utils.MetaDefault: db}, cfg.DbCfg())
	dm := NewDataManager(dbCM, cfg, nil)
	//set 4 attr profiles with different filters to index them

	attrPrf1 := &utils.AttributeProfile{
		Tenant:    "cgrates.org",
		ID:        "AttrPrf1",
		FilterIDs: []string{"*string:~*req.Account:1001", "*ai:~*req.AnswerTime:2014-07-29T15:00:00Z", "*string:~*opts.*context:con1|con2|con3"},
		Attributes: []*utils.Attribute{
			{
				FilterIDs: []string{"*string:~*req.Field1:Initial"},
				Path:      utils.MetaReq + utils.NestingSep + "Field1",
				Type:      utils.MetaVariable,
				Value:     utils.NewRSRParsersMustCompile("Sub1", utils.InfieldSep),
			},
		},
		Blockers: utils.DynamicBlockers{
			{
				Blocker: true,
			},
		},
		Weights: utils.DynamicWeights{
			{
				Weight: 20,
			},
		},
	}

	attrPrf2 := &utils.AttributeProfile{
		Tenant:    "cgrates.org",
		ID:        "AttrPrf2",
		FilterIDs: []string{"*string:~*resources.RES_GRP1.Available:4"},
		Attributes: []*utils.Attribute{
			{
				Path:  utils.MetaReq + utils.NestingSep + "Password",
				Type:  utils.MetaVariable,
				Value: utils.NewRSRParsersMustCompile("admin", utils.InfieldSep),
			},
		},
		Blockers: utils.DynamicBlockers{
			{
				Blocker: true,
			},
		},
		Weights: utils.DynamicWeights{
			{
				Weight: 20,
			},
		},
	}

	attrPrf3 := &utils.AttributeProfile{
		Tenant:    "cgrates.org",
		ID:        "AttrPrf3",
		FilterIDs: []string{"*prefix:~*req.Destination:1007", "*string:~*req.Account:1001", "*string:~*opts.TotalCost:~*stats.STS_PRF1.*tcc"},
		Attributes: []*utils.Attribute{
			{
				Path:  utils.MetaReq + utils.NestingSep + "RequestType",
				Type:  utils.MetaVariable,
				Value: utils.NewRSRParsersMustCompile("*rated", utils.InfieldSep),
			},
		},
		Blockers: utils.DynamicBlockers{
			{
				Blocker: true,
			},
		},
		Weights: utils.DynamicWeights{
			{
				Weight: 20,
			},
		},
	}

	attrPrf4 := &utils.AttributeProfile{
		Tenant:    "cgrates.org",
		ID:        "AttrPrf4",
		FilterIDs: []string{"*prefix:~*req.Destination:1007", "*prefix:~*accounts.RES_GRP1.Available:10"},
		Attributes: []*utils.Attribute{
			{
				Path:  utils.MetaReq + utils.NestingSep + "TCC",
				Type:  utils.MetaVariable,
				Value: utils.NewRSRParsersMustCompile("203", utils.InfieldSep),
			},
		},
		Blockers: utils.DynamicBlockers{
			{
				Blocker: true,
			},
		},
		Weights: utils.DynamicWeights{
			{
				Weight: 20,
			},
		},
	}

	if err := dm.SetAttributeProfile(context.Background(), attrPrf1, true); err != nil {
		t.Error(err)
	} else if err := dm.SetAttributeProfile(context.Background(), attrPrf2, true); err != nil {
		t.Error(err)
	} else if err := dm.SetAttributeProfile(context.Background(), attrPrf3, true); err != nil {
		t.Error(err)
	} else if err := dm.SetAttributeProfile(context.Background(), attrPrf4, true); err != nil {
		t.Error(err)
	}

	expIDx := map[string]utils.StringSet{
		"*prefix:*req.Destination:1007": {
			"AttrPrf3": {},
			"AttrPrf4": {},
		},
		"*string:*req.Account:1001": {
			"AttrPrf3": {},
			"AttrPrf1": {},
		},
		"*string:*opts.*context:con1": {
			"AttrPrf1": {},
		},
		"*string:*opts.*context:con2": {
			"AttrPrf1": {},
		},
		"*string:*opts.*context:con3": {
			"AttrPrf1": {},
		},
	}
	if fltrIDx, err := dm.GetIndexes(context.Background(), utils.CacheAttributeFilterIndexes,
		"cgrates.org", utils.EmptyString, utils.NonTransactional, true, true); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(expIDx, fltrIDx) {
		t.Errorf("Expected %+v, received %+v", utils.ToJSON(expIDx), utils.ToJSON(fltrIDx))
	}
}

func TestFilterIndexesCheckingDynamicPathToNotIndexLibphNmbr(t *testing.T) {
	Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	db, _ := NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
	dbCM := NewDBConnManager(map[string]DataDB{utils.MetaDefault: db}, cfg.DbCfg())
	dm := NewDataManager(dbCM, cfg, nil)

	// set 1 charger profile with different *libphonenumber filter to index
	cghPfr := &utils.ChargerProfile{
		Tenant: "cgrates.org",
		ID:     "CHARGER_2",
		FilterIDs: []string{
			"*prefix:~*opts.*originID:TEST_ID",
			"*string:~*opts.TotalCost:~*stats.STS_PRF1.*tcc",
			"*string:~*libphonenumber.<~*req.Destination>:1233",
		},
		RunID:        "RAW",
		AttributeIDs: []string{"attr_1"},
		Weights: utils.DynamicWeights{
			{
				Weight: 10,
			},
		},
	}

	if err := dm.SetChargerProfile(context.Background(), cghPfr, true); err != nil {
		t.Error(err)
	}

	expIDx := map[string]utils.StringSet{
		"*prefix:*opts.*originID:TEST_ID": {
			"CHARGER_2": {},
		},
	}
	if fltrIDx, err := dm.GetIndexes(context.Background(), utils.CacheChargerFilterIndexes,
		"cgrates.org", utils.EmptyString, utils.NonTransactional, true, true); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(expIDx, fltrIDx) {
		t.Errorf("Expected %+v, received %+v", utils.ToJSON(expIDx), utils.ToJSON(fltrIDx))
	}
}
