package org

import (
	"context"
	"strconv"
	"strings"

	"github.com/duke-git/lancet/convertor"
	"github.com/duke-git/lancet/v2/slice"

	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"

	"github.com/spf13/viper"
	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

type ExpWhiteListParam struct {
	OrgId       string
	EmailSuffix string
}

type ExpItem struct {
	OrgIds       string `yaml:"orgIds"`
	EmailSuffixs string `yaml:"emailSuffixs"`
	MinOrgId     string `yaml:"minOrgId"`
}

func GetEmailSuffix(email string) string {
	res := strings.Split(email, "@")
	if len(res) != 2 {
		return ""
	}
	return res[1]
}
func isHitMinId(ctx context.Context, checkIdStr string, minIdStr string) bool {
	logger := log.WithContextL(ctx)
	if checkIdStr == "" || minIdStr == "" {
		return false
	}
	checkId, err := strconv.ParseUint(checkIdStr, 10, 64)
	if err != nil {
		logger.Error("isHitMinId failed.", zap.String("checkIdStr", checkIdStr))
		return false
	}
	minId, err := strconv.ParseUint(minIdStr, 10, 64)
	if err != nil {
		logger.Error("isHitMinId failed.", zap.String("minIdStr", minIdStr))
		return false
	}
	return minId < checkId
}
func isHitIdList(checkId string, idListStr string) bool {
	if checkId == "" {
		return false
	}
	idList := strings.Split(idListStr, ",")
	for _, id := range idList {
		if id == checkId {
			return true
		}
	}
	return false
}

func isHitExpItem(ctx context.Context, req *ExpWhiteListParam, expItem *ExpItem) bool {
	return isHitMinId(ctx, req.OrgId, expItem.MinOrgId) ||
		isHitIdList(req.OrgId, expItem.OrgIds) || isHitIdList(req.EmailSuffix, expItem.EmailSuffixs)
}

func GetExpConfByName(ctx context.Context, inputExpName string) (*ExpItem, error) {
	var expItems map[string]ExpItem
	logger := log.WithContextL(ctx)
	parseErr := viper.UnmarshalKey("expWhiteList", &expItems)
	if parseErr != nil {
		logger.Error("parse expwhitelist failed.", zap.Error(parseErr))
		return nil, parseErr
	}
	item, exists := expItems[inputExpName]
	if !exists {
		logger.Error("no item found in expitems.", zap.String("exp_name", inputExpName))
		return nil, errs.NewBadRequest("no item found in expitems.", nil)
	}
	return &item, nil
}

func IsHitExp(ctx context.Context, inputExpName string, req *ExpWhiteListParam) (bool, error) {
	var expItems map[string]ExpItem
	logger := log.WithContextL(ctx)
	parseErr := viper.UnmarshalKey("expWhiteList", &expItems)
	if parseErr != nil {
		logger.Error("parse expwhitelist failed.", zap.Error(parseErr))
		return false, parseErr
	}
	for expName, expItem := range expItems {
		if inputExpName == expName && isHitExpItem(ctx, req, &expItem) {
			logger.Info("HitExpItem", zap.String("expName", expName), zap.Any("req", req), zap.Any("expItem", expItem))
			return true, nil
		}
	}
	return false, nil
}

func GetHitExpList(ctx context.Context, req *ExpWhiteListParam) ([]string, error) {
	var hitExps []string
	var expItems map[string]ExpItem
	logger := log.WithContextL(ctx)
	parseErr := viper.UnmarshalKey("expWhiteList", &expItems)
	if parseErr != nil {
		return nil, parseErr
	}
	for expName, expItem := range expItems {
		if isHitExpItem(ctx, req, &expItem) {
			logger.Info("HitExpItem", zap.String("expName", expName), zap.Any("req", req), zap.Any("expItem", expItem))
			hitExps = append(hitExps, expName)
		}
	}

	return hitExps, nil
}

func GetHitOrgWhiteList(ctx context.Context, orgId uint64) []string {
	var list []string
	auditLogOrgs := viper.GetStringSlice("server.enableAuditLog")
	enableXAccountOrgs := viper.GetStringSlice("server.enableXAccount")
	enableReplicationOrgs := viper.GetStringSlice("server.enableReplication")
	if slice.Contain(auditLogOrgs, convertor.ToString(orgId)) {
		list = append(list, "account_enable_audit_log_org")
	}
	if slice.Contain(enableXAccountOrgs, convertor.ToString(orgId)) {
		list = append(list, "account_enable_xAccount_org")
	}
	if slice.Contain(enableReplicationOrgs, convertor.ToString(orgId)) {
		list = append(list, "account_enable_replication_org")
	}
	//tilog.Info(ctx, "get viper", zap.Any("openAPIOrgs", openAPIOrgs), zap.Any("auditLogOrgs", auditLogOrgs))
	tilog.Info(ctx, "get GetHitOrgWhiteList result", zap.Any("list", list))
	return list
}
