package dbuser

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/tidbcloud/account/commons/config"
	"gorm.io/gorm"

	"go.uber.org/zap"

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

	"github.com/tidbcloud/account/central/utils"

	"github.com/tidbcloud/account/internel/dao/dbuser"
	dbUserDao "github.com/tidbcloud/account/internel/dao/dbuser"
	"github.com/tidbcloud/account/internel/dao/entity"
)

func (r *DBUserSvc) CreateOrgKey(ctx context.Context, orgId uint64, keyId string, status entity.OrgKeyStatus) error {

	return r.hub.DBUser.CreateOrgKey(ctx, r.db, orgId, keyId, status)
}

func (r *DBUserSvc) ListOrgKeys(ctx context.Context, filter dbuser.OrgKeyFilter) ([]entity.OrgKey, error) {

	return r.hub.DBUser.ListOrgKeys(ctx, r.db, filter)
}

func (r *DBUserSvc) UpdateOrgKey(ctx context.Context, orgId uint64, keyId string, status entity.OrgKeyStatus) error {

	return r.hub.DBUser.UpdateOrgKey(ctx, r.db, orgId, keyId, status)
}

func (r *DBUserSvc) DeleteOrgKey(ctx context.Context, orgId uint64) error {

	return r.hub.DBUser.DeleteOrgKey(ctx, r.db, orgId)
}

func (r *DBUserSvc) GetPublicKeysByOrgId(ctx context.Context, orgId uint64) (string, error) {
	filter := dbUserDao.OrgKeyFilter{
		Status: []entity.OrgKeyStatus{entity.OrgKeyStatusActive, entity.OrgKeyStatusDelete},
		OrgIDs: []entity.ID{entity.ID(orgId)},
	}

	orgKeys, err := r.hub.DBUser.ListOrgKeys(ctx, r.db, filter)
	if err != nil {
		tilog.Warn(ctx, "ListOrgKeys warn, query record error",
			zap.Any("query filter", fmt.Sprintf("%#v", filter)))
		return "", err
	}
	str := ""
	if len(orgKeys) > 0 {
		keyIds := []string{}
		for _, k := range orgKeys {
			if k.Status == entity.OrgKeyStatusDelete && time.Since(*k.UpdatedAt).Minutes() > 30 {
				tilog.Info(ctx, "getPublicKeys , this  orgKey delete more than 30 minute , skip ",
					zap.Any("orgKey", k))
				continue

			}
			keyIds = append(keyIds, k.KeyID)
		}
		str = utils.GetPublicKeyByKeyId(keyIds)
	} else {
		tilog.Info(ctx, "ListOrgKeys warn, query record is not exits",
			zap.Any("query filter", fmt.Sprintf("%#v", filter)))
	}
	tilog.Info(ctx, "GetPublicKeysByOrgId ", zap.Any("orgId", orgId), zap.Any("keys", str))
	return str, nil
}

func (r *DBUserSvc) GetClusterAuthPubKey(ctx context.Context, orgId, clusterId uint64, isDevTier bool) (string, error) {
	tilog.Info(ctx, "GetClusterAuthPubKey", zap.Any("orgId", orgId), zap.Any("clusterId", clusterId), zap.Any("isDevTier", isDevTier))
	if isDevTier {
		orgId = config.ShareKeyOrg
	}
	keys, err := r.GetPublicKeysByOrgId(ctx, orgId)
	tilog.Info(ctx, "GetClusterAuthPubKey GetPublicKeysByOrgId result", zap.Any("orgId", orgId), zap.Any("keys", keys), zap.Any("err", err))
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		tilog.Error(ctx, "GetClusterAuthPubKey error", zap.Any("orgId", orgId), zap.Any("err", err))
		return "", err
	}
	if keys != "" {
		return keys, nil
	}

	err = r.CreateKmsKeyAndUpdateRecord(ctx, entity.CommandOrgKey{
		OrgID: entity.ID(orgId),
	})
	if err != nil {
		tilog.Error(ctx, "GetClusterAuthPubKey CreateKmsKeyAndUpdateRecord error", zap.Any("orgId", orgId), zap.Any("err", err))
		return "", err
	}
	keys, err = r.GetPublicKeysByOrgId(ctx, orgId)
	tilog.Info(ctx, "GetClusterAuthPubKey second GetPublicKeysByOrgId result", zap.Any("orgId", orgId), zap.Any("keys", keys), zap.Any("err", err))

	return keys, err
}
