package integration

import (
	"context"

	"github.com/DataDog/datadog-api-client-go/api/v1/datadog"

	"github.com/pingcap/dbaas/central/db"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/tidbcloud/idl/pbgen/proto/central"
	"github.com/tidbcloud/pkgv2/secret/encrypt"
	"gorm.io/gorm"
)

// Model encapsulates the all business logics and contexts for integrations.
// Note: no error logs here. We log errors in the service layer.
type Model struct {
	encryptor  encrypt.Encryptor
	datadogApi *datadog.APIClient
}

func NewModel(encryptor encrypt.Encryptor) Model {
	configuration := datadog.NewConfiguration()
	apiClient := datadog.NewAPIClient(configuration)

	return Model{
		encryptor:  encryptor,
		datadogApi: apiClient,
	}
}

// ListIntegrations returns the status of the integrations for a given customer project.
func (m Model) ListIntegrations(ctx context.Context, _ uint64, projectId uint64, providerType central.IntegrationType) ([]*central.IntegrationStatusResp, error) {
	// Get status from metadb.
	is := make([]entity.Integration, 0)
	err := db.Transaction(func(tx *gorm.DB) error {
		q := entity.NewIntegrationQuerySet(tx).ProjectIDEq(entity.ID(projectId))
		if providerType != 0 {
			q = q.ProviderTypeEq(entity.IntegrationType(providerType))
		}
		return q.All(&is)
	})
	if err != nil {
		return nil, err
	}

	// Map entity models to api models.
	results := make([]*central.IntegrationStatusResp, 0, len(is))
	for _, i := range is {

		if i.Status != entity.IntegrationStatusActive && i.Status != entity.IntegrationStatusError {
			// We only return active integration records.
			continue
		}

		if len(i.EncryptedDatadogApiKey) > 0 {
			// If the integration is datadog, validate api key.
			decryptedKey, err := encrypt.DecryptBase64(m.encryptor, i.EncryptedDatadogApiKey)
			if err != nil {
				return nil, err
			}
			valid, err := m.ValidateDatadogAPIKey(ctx, decryptedKey.String(), SiteDBToRest(i.DatadogSite))
			if err != nil || !valid {
				i.StatusReason = "Invalid api key"
				i.Status = entity.IntegrationStatusError
				err := db.Transaction(func(tx *gorm.DB) error {
					return i.Update(tx, entity.IntegrationDBSchema.Status, entity.IntegrationDBSchema.StatusReason)
				})
				if err != nil {
					return nil, err
				}
			}
		}

		ps := make([]central.IntegrationPayload, 0, len(i.Payloads.Payloads))
		for _, p := range i.Payloads.Payloads {
			ps = append(ps, payloadDBToRest(p))
		}

		results = append(results, &central.IntegrationStatusResp{
			Type:                typeDBToRest(i.ProviderType),
			Status:              statusDBToRest(i.Status),
			StatusReason:        i.StatusReason,
			Payloads:            ps,
			DatadogSite:         SiteDBToRest(i.DatadogSite),
			DatadogSiteUrl:      GetDatadogSiteUrl(SiteDBToRest(i.DatadogSite)),
			DatadogDashboardUrl: GetDatadogDashboardUrl(SiteDBToRest(i.DatadogSite)),
			DatadogMaskedApiKey: i.MaskedDatadogApiKey,
		})
	}

	return results, nil
}
