package uncutils

import (
	"fmt"
	"time"

	"slices"

	"github.com/google/uuid"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/novuhandler"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/pingcap/log"
	"go.uber.org/zap"
)

// event for send unc notification
const (
	ReachedOrgBudgetThreshold     = "reached-budget-threshold"
	ReachedProjectBudgetThreshold = "reached-project-budget-threshold"
	ReachedClusterBudgetThreshold = "reached-cluster=budget-threshold"
	OpenCreditPackage             = "open-credit-package"
	ExhaustCreditPackage          = "exhaust-credit-package"
	ReclaimCreditPackage          = "reclaim-credit-package"
	ExpireCreditPackage           = "expire-credit-package"
	UpdateDiscount                = "update-discount"
	ExpireDiscount                = "expire-discount"
	ReclaimDiscount               = "reclaim-discount"
	DirectToMSPCustomer           = "direct-to-msp-customer"
	DirectToCPPOCustomer          = "direct-to-cppo-customer"
	DirectToMCPOCustomer          = "direct-to-mcpo-customer"
	MarketplaceSubscribe          = "marketplace-subscribe"
	MarketplaceUnsubscribe        = "marketplace-unsubscribe"
	ChangeBindedSupportPlan       = "change-binded-support-plan"
	ServerlessClusterCreated      = "serverless-cluster-created"
	ServerlessClusterDeleted      = "serverless-cluster-deleted"
	DedicatedClusterCreated       = "dedicated-cluster-created"
	DedicatedClusterDeleted       = "dedicated-cluster-deleted"
	PremiumClusterCreated         = "premium-cluster-created"
	PremiumClusterDeleted         = "premium-cluster-deleted"
	EssentialClusterCreated       = "essential-cluster-created"
	EssentialClusterDeleted       = "essential-cluster-deleted"
	StarterClusterCreated         = "starter-cluster-created"
	StarterClusterDeleted         = "starter-cluster-deleted"
	PaymentActionRequired         = "payment-action-required"
)

type idConfig struct {
	dev     string
	staging string
	prod    string
}

type templateConfig struct {
	workflowId   idConfig
	triggerId    idConfig
	roles        []string // roles, used for org scope
	projectRoles []string // project roles, used for project scope
}

var envTemplates = map[string]templateConfig{
	ReachedOrgBudgetThreshold: {
		workflowId: idConfig{
			dev:     "675a8d66f7bd3d981239db99",
			staging: "676a1927749ddd4d7404e432",
			prod:    "676a257e201849286e738bd3",
		},
		triggerId: idConfig{
			dev:     "budge-alert",
			staging: "threshold-of-your-organizations-budget-reached",
			prod:    "threshold-of-your-organizations-budget-reached",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	ReachedProjectBudgetThreshold: {
		workflowId: idConfig{
			dev:     "67720c3df7bd3d98123b6d66",
			staging: "677214da749ddd4d740501de",
			prod:    "6772154e6e82f412f98b6d04",
		},
		triggerId: idConfig{
			dev:     "threshold-of-your-projects-budget-reached",
			staging: "threshold-of-your-projects-budget-reached",
			prod:    "threshold-of-your-projects-budget-reached",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{constant.UserRoleProjectOwner},
	},
	ReachedClusterBudgetThreshold: {
		workflowId: idConfig{
			dev:     "67720db1f7bd3d98123b6e6b",
			staging: "67721480749ddd4d74050189",
			prod:    "677215cb6e82f412f98b6d5e",
		},
		triggerId: idConfig{
			dev:     "threshold-of-your-serverless-spending-limit-budget-reached",
			staging: "threshold-of-your-serverless-spending-limit-budget-reached",
			prod:    "threshold-of-your-serverless-spending-limit-budget-reached",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{constant.UserRoleProjectOwner},
	},
	OpenCreditPackage: {
		workflowId: idConfig{
			dev:     "67629105f7bd3d98123a52a1",
			staging: "676a1a44749ddd4d7404e573",
			prod:    "676a25f26e82f412f98b421a",
		},
		triggerId: idConfig{
			dev:     "credits-assigned-to-your-organization",
			staging: "credits-assigned-to-your-organization",
			prod:    "credits-assigned-to-your-organization",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	ExhaustCreditPackage: {
		workflowId: idConfig{
			dev:     "676292b3f7bd3d98123a5371",
			staging: "676a1ab9749ddd4d7404e5bc",
			prod:    "676a26546e82f412f98b4252",
		},
		triggerId: idConfig{
			dev:     "credits-assigned-to-your-organization-have-been-fully-used",
			staging: "credits-assigned-to-your-organization-have-been-fully-used",
			prod:    "credits-assigned-to-your-organization-have-been-fully-used",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	ReclaimCreditPackage: {
		workflowId: idConfig{
			dev:     "67629346f7bd3d98123a543c",
			staging: "676a1b43749ddd4d7404e5ff",
			prod:    "676a26d66e82f412f98b42a0",
		},
		triggerId: idConfig{
			dev:     "credits-reclaimed-from-your-organization",
			staging: "credits-reclaimed-from-your-organization",
			prod:    "credits-reclaimed-from-your-organization",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	ExpireCreditPackage: {
		workflowId: idConfig{
			dev:     "676293a2f7bd3d98123a5498",
			staging: "676a1bf3749ddd4d7404e642",
			prod:    "676a272d201849286e738c64",
		},
		triggerId: idConfig{
			dev:     "credits-assigned-to-your-organization-have-expired",
			staging: "credits-assigned-to-your-organization-have-expired",
			prod:    "credits-assigned-to-your-organization-have-expired",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	UpdateDiscount: {
		workflowId: idConfig{
			dev:     "6762944ef7bd3d98123a5509",
			staging: "676a1c89749ddd4d7404e685",
			prod:    "676a28276e82f412f98b42fe",
		},
		triggerId: idConfig{
			dev:     "discount-assigned-to-your-organization-3zdcpVMQG",
			staging: "discount-assigned-to-your-organization",
			prod:    "discount-assigned-to-your-organization",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	ExpireDiscount: {
		workflowId: idConfig{
			dev:     "6762959df7bd3d98123a568c",
			staging: "676a1f37749ddd4d7404e770",
			prod:    "676a290a6e82f412f98b4395",
		},
		triggerId: idConfig{
			dev:     "discount-assigned-to-your-organization-has-expired",
			staging: "discount-assigned-to-your-organization-has-expired",
			prod:    "discount-assigned-to-your-organization-has-expired",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	ReclaimDiscount: {
		workflowId: idConfig{
			dev:     "676297b2f7bd3d98123a5bce",
			staging: "676a1fbf749ddd4d7404e801",
			prod:    "676a29e86e82f412f98b4429",
		},
		triggerId: idConfig{
			dev:     "discount-reclaimed-from-your-organization",
			staging: "discount-reclaimed-from-your-organization",
			prod:    "discount-reclaimed-from-your-organization",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer},
		projectRoles: []string{},
	},
	DirectToMSPCustomer: {
		workflowId: idConfig{
			dev:     "67629830f7bd3d98123a5c1d",
			staging: "676a22c2749ddd4d7404e94f",
			prod:    "676a2b096e82f412f98b4496",
		},
		triggerId: idConfig{
			dev:     "your-organization-is-now-linked-with-a-managed-service-partner",
			staging: "your-organization-is-now-linked-with-a-managed-service-partner",
			prod:    "your-organization-is-now-linked-with-a-managed-service-partner",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer, constant.UserRoleMember, constant.UserRoleAuditAdmin},
		projectRoles: []string{},
	},
	DirectToCPPOCustomer: {
		workflowId: idConfig{
			dev:     "67629aa7f7bd3d98123a5cd9",
			staging: "676a233d749ddd4d7404e995",
			prod:    "676a2b83201849286e738e1a",
		},
		triggerId: idConfig{
			dev:     "your-organization-is-now-linked-with-a-managed-service-partner-fLD3zb4Xb",
			staging: "your-organization-subscribed-to-tidb-cloud-via-aws-cppo",
			prod:    "your-organization-subscribed-to-tidb-cloud-via-aws-cppo",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer, constant.UserRoleMember, constant.UserRoleAuditAdmin},
		projectRoles: []string{},
	},
	MarketplaceSubscribe: {
		workflowId: idConfig{
			dev:     "67612b6bf7bd3d98123a3128",
			staging: "676a204e749ddd4d7404e850",
			prod:    "676a2f936e82f412f98b4573",
		},
		triggerId: idConfig{
			dev:     "your-organization-successfully-subscribed-tidb-cloud",
			staging: "subscribed-to-tidb-cloud-via-marketplace-sucessfully",
			prod:    "successfully-subscribed-to-tidb-cloud-via-marketplace",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer, constant.UserRoleMember, constant.UserRoleAuditAdmin},
		projectRoles: []string{},
	},
	MarketplaceUnsubscribe: {
		workflowId: idConfig{
			dev:     "67612cc6f7bd3d98123a3239",
			staging: "676a214c749ddd4d7404e8c6",
			prod:    "676a2fc5201849286e738f11",
		},
		triggerId: idConfig{
			dev:     "your-organization-successfully-unsubscribed-from-tidb-cloud",
			staging: "successfully-unsubscribed-from-tidb-cloud-via-marketplace",
			prod:    "successfully-unsubscribed-from-tidb-cloud-via-marketplace",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer, constant.UserRoleMember, constant.UserRoleAuditAdmin},
		projectRoles: []string{},
	},
	ChangeBindedSupportPlan: {
		workflowId: idConfig{
			dev:     "675bab9df7bd3d981239efd5",
			staging: "676a222d749ddd4d7404e90c",
			prod:    "676a2a7d201849286e738db2",
		},
		triggerId: idConfig{
			dev:     "bindedsupportplan-update",
			staging: "your-organizations-subscription-to-support-plan-has-been-changed",
			prod:    "your-organizations-subscription-to-support-plan-has-been-changed",
		},
		roles:        []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin, constant.UserRoleOrgBillingViewer, constant.UserRoleMember, constant.UserRoleAuditAdmin},
		projectRoles: []string{},
	},
	ServerlessClusterCreated: {
		workflowId: idConfig{
			dev:     "67737b1bf7bd3d98123b91b5",
			staging: "6773aaa4749ddd4d74051219",
			prod:    "6773ac286e82f412f98b7298",
		},
		triggerId: idConfig{
			dev:     "your-cluster-is-ready-to-use-sf9OMhGFO",
			staging: "your-cluster-is-ready-to-use-tQVp1vks1",
			prod:    "your-cluster-is-ready-to-use-tW1VKPVNR",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	ServerlessClusterDeleted: {
		workflowId: idConfig{
			dev:     "67737b60f7bd3d98123b9206",
			staging: "6773aaea749ddd4d7405126f",
			prod:    "6773ac71201849286e73bb72",
		},
		triggerId: idConfig{
			dev:     "your-cluster-has-been-successfully-deleted-IYQt4qcqD",
			staging: "your-cluster-has-been-successfully-deleted-UzCA2Hvfv",
			prod:    "your-cluster-has-been-successfully-deleted-BN1siO6CC",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	DedicatedClusterCreated: {
		workflowId: idConfig{
			dev:     "677379eaf7bd3d98123b9109",
			staging: "6773a9ed749ddd4d74051176",
			prod:    "6773ab79201849286e73bacd",
		},
		triggerId: idConfig{
			dev:     "your-cluster-is-ready-to-use",
			staging: "your-cluster-is-ready-to-use",
			prod:    "your-cluster-is-ready-to-use",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	DedicatedClusterDeleted: {
		workflowId: idConfig{
			dev:     "67737abef7bd3d98123b9169",
			staging: "6773aa36749ddd4d740511c3",
			prod:    "6773abbf201849286e73bb08",
		},
		triggerId: idConfig{
			dev:     "your-cluster-has-been-successfully-deleted",
			staging: "your-cluster-has-been-successfully-deleted",
			prod:    "your-cluster-has-been-successfully-deleted",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	PremiumClusterCreated: {
		workflowId: idConfig{
			dev:     "6882f5d38459f7fb00d97140",
			staging: "6888c417befafb31c1822b0c",
			prod:    "68898eea1f1b498b851bf09f",
		},
		triggerId: idConfig{
			dev:     "your-cluster-is-ready-to-use-AKgONViYV",
			staging: "your-cluster-is-ready-to-use-sCiv2j7v7",
			prod:    "your-premium-tidb-is-ready-to-use",
		},
		roles: []string{constant.UserRoleOwner},
	},
	PremiumClusterDeleted: {
		workflowId: idConfig{
			dev:     "6882f63d8459f7fb00d97202",
			staging: "6888c568befafb31c1822ba7",
			prod:    "6889900c1f1b498b851bf19b",
		},
		triggerId: idConfig{
			dev:     "your-cluster-has-been-successfully-deleted-QFEGrTq2w",
			staging: "your-cluster-has-been-successfully-deleted-peYOBFFxT",
			prod:    "your-premium-tidb-has-been-successfully-deleted",
		},
		roles: []string{constant.UserRoleOwner},
	},

	EssentialClusterCreated: {
		workflowId: idConfig{
			dev:     "68995b25db396feac5afc73d",
			staging: "689999fb30d58ae88f6d86c5",
			prod:    "68999b1c7cf4aaed9a4f6e26",
		},
		triggerId: idConfig{
			dev:     "your-essential-cluster-is-ready-to-use",
			staging: "your-essential-cluster-is-ready-to-use",
			prod:    "your-essential-cluster-is-ready-to-use",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	EssentialClusterDeleted: {
		workflowId: idConfig{
			dev:     "68995b71db396feac5afc7e5",
			staging: "68999a3730d58ae88f6d8710",
			prod:    "68999b587cf4aaed9a4f6e76",
		},
		triggerId: idConfig{
			dev:     "your-essential-cluster-has-been-successfully-deleted",
			staging: "your-essential-cluster-has-been-successfully-deleted",
			prod:    "your-essential-cluster-has-been-successfully-deleted",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},

	StarterClusterCreated: {
		workflowId: idConfig{
			dev:     "68995938db396feac5afc576",
			staging: "6899995b30d58ae88f6d8607",
			prod:    "68999a987cf4aaed9a4f6d42",
		},
		triggerId: idConfig{
			dev:     "your-cluster-is-ready-to-use-yaW1mVvlB",
			staging: "your-starter-cluster-is-ready-to-use",
			prod:    "your-starter-cluster-is-ready-to-use",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	StarterClusterDeleted: {
		workflowId: idConfig{
			dev:     "68995a76db396feac5afc66a",
			staging: "689999af30d58ae88f6d8680",
			prod:    "68999ad97cf4aaed9a4f6db8",
		},
		triggerId: idConfig{
			dev:     "your-starter-cluster-has-been-successfully-deleted",
			staging: "your-starter-cluster-has-been-successfully-deleted",
			prod:    "your-starter-cluster-has-been-successfully-deleted",
		},
		roles:        []string{constant.UserRoleOwner},
		projectRoles: []string{constant.UserRoleProjectOwner, constant.UserRoleProjectCtlPlaneViewer, constant.UserRoleProjectReadOnly, constant.UserRoleProjectDev},
	},
	PaymentActionRequired: {
		workflowId: idConfig{
			dev:     "6931ab23f05519a7075f7f27",
			staging: "6931aba70617ef2dba5fc6da",
			prod:    "692fa3934382e924c350e3b1",
		},
		triggerId: idConfig{
			dev:     "credit-card-payment-failed-due-to-3ds-security",
			staging: "credit-card-payment-failed-due-to-3ds-security",
			prod:    "credit-card-payment-failed-due-to-3ds-security",
		},
		roles: []string{constant.UserRoleOwner, constant.UserRoleBillingAdmin},
	},
}

func SendInAppNotification(tenantID uint, event string, payload map[string]string) {
	if !config.Get().GetBool(config.InAPPNotificationEnable) {
		log.Info("forbiden to send in-app notification", zap.Uint("tenantID", tenantID), zap.String("event", event))
		return
	}
	template, exists := envTemplates[event]
	if !exists {
		log.Error("fail to send in-app notification, unc template not exist", zap.Uint("tenantID", tenantID), zap.String("event", event))
		return
	}
	workflowId := template.workflowId.prod
	triggerId := template.triggerId.prod
	if config.Get().Get(config.ENV) == constant.ENV_DEV {
		workflowId = template.workflowId.dev
		triggerId = template.triggerId.dev
	}
	if config.Get().Get(config.ENV) == constant.ENV_STAGING {
		workflowId = template.workflowId.staging
		triggerId = template.triggerId.staging
	}
	// deal with org and project roles
	orgRoles := slices.Clone(template.roles)            // copy roles to orgRoles
	projectRoles := slices.Clone(template.projectRoles) // copy project roles to projectRoles
	// gen transactionID, to deduplication
	transactionId := uuid.NewString()
	// firstly, send notification for org roles
	if len(orgRoles) != 0 {
		log.Info("start to send in-app notification for org roles", zap.Uint("tenantID", tenantID), zap.String("event", event), zap.String("workflowId", workflowId), zap.String("triggerId", triggerId), zap.String("transactionId", transactionId), zap.Any("payload", payload), zap.Any("roles", orgRoles))
		_, err := novuhandler.Get().BulkTriggerEvent(tenantID, forms.Trigger{
			IsSendNow:     true,
			ScheduleTime:  timeutils.GetNow().Add(30 * time.Second),
			Operator:      "Billing",
			Roles:         orgRoles,
			TargetIDList:  []string{fmt.Sprintf("%d", tenantID)},
			TriggerID:     triggerId,
			WorkFlowID:    workflowId,
			ScopeType:     constant.ScopeOrg,
			Payload:       payload,
			TransactionId: transactionId,
		})
		if err != nil {
			log.Error("error to send in-app notification for org roles", zap.Uint("tenantID", tenantID), zap.String("event", event), zap.Error(err))
		}
	}
	// then, send notification for project roles
	if len(projectRoles) != 0 {
		// check projectId, it is stored in payload
		if projectId, exists := payload["projectId"]; !exists || projectId == "" {
			log.Error("failed to send in-app notification for project roles, projectId not exists", zap.Uint("tenantID", tenantID), zap.String("event", event), zap.Any("payload", payload))
			return
		}
		log.Info("start to send in-app notification for project roles", zap.Uint("tenantID", tenantID), zap.String("event", event), zap.String("workflowId", workflowId), zap.String("triggerId", triggerId), zap.String("transactionId", transactionId), zap.Any("payload", payload), zap.Any("roles", projectRoles))
		_, err := novuhandler.Get().BulkTriggerEvent(tenantID, forms.Trigger{
			IsSendNow:     true,
			ScheduleTime:  timeutils.GetNow().Add(30 * time.Second),
			Operator:      "Billing",
			Roles:         projectRoles,
			TargetIDList:  []string{payload["projectId"]},
			TriggerID:     triggerId,
			WorkFlowID:    workflowId,
			ScopeType:     constant.ScopeProject,
			Payload:       payload,
			TransactionId: transactionId,
		})
		if err != nil {
			log.Error("error to send in-app notification for project roles", zap.Uint("tenantID", tenantID), zap.String("event", event), zap.Error(err))
		}
	}
}
