package resourcepool

import (
	"context"
	"regexp"
	"strconv"
	"time"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	resourcepoolrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
)

var keepTagRegex = regexp.MustCompile(`keep-(\d+)([hd])`)

func (w *worker) deleteIfOverIdleTtl(ctx context.Context, idlePool *resourcepoolrepo.IdleInfo) (bool, error) {
	now := time.Now().UTC()

	resourcePool, err := w.resourcePoolRepo.Load(ctx, idlePool.ResourcePoolId, false)
	if err != nil {
		tilog.Error(ctx, "failed to load resource pool",
			zap.Error(err),
			zap.Uint64("resource_pool_id", idlePool.ResourcePoolId))
		return false, err
	}

	if resourcePool.OwnerType != globalngv1.ResourcePool_ORGANIZATION {
		tilog.Info(ctx, "resource pool is not owned by customer")
		return false, nil
	}

	if resourcePool.ServicePlan == globalcommonv1.ServicePlan_BYOC {
		tilog.Info(ctx, "resource pool is BYOC, skipping deletion",
			zap.Uint64("resource_pool_id", idlePool.ResourcePoolId),
			zap.Uint64("org_id", resourcePool.OwnerId))
		return false, nil
	}

	quota, err := w.rcuQuotaRepo.Load(ctx, resourcePool.OwnerId, resourcePool.ServicePlan.String())
	if err != nil || quota == nil {
		tilog.Error(ctx, "failed to load tenant quota",
			zap.Error(err),
			zap.String("service_plan", resourcePool.ServicePlan.String()),
			zap.Uint64("org_id", resourcePool.OwnerId))
		return false, err
	}

	if quota.IdleResourcePoolTtlInHours == 0 {
		tilog.Info(ctx, "idle resource pool ttl is not set, skipping deletion",
			zap.Uint64("resource_pool_id", idlePool.ResourcePoolId),
			zap.Uint64("org_id", resourcePool.OwnerId))
		return false, nil
	}

	idleDurationSeconds := now.Sub(idlePool.IdleStartTime).Seconds()

	// check if idle duration exceeds quota
	if idleDurationSeconds < float64(3600*quota.IdleResourcePoolTtlInHours) {
		tilog.Info(ctx, "resource pool is still within retention period, skipping deletion",
			zap.Uint64("resource_pool_id", idlePool.ResourcePoolId),
			zap.Uint64("org_id", resourcePool.OwnerId),
			zap.Float64("idle_duration_s", idleDurationSeconds),
			zap.Uint64("idle_ttl_hours", quota.IdleResourcePoolTtlInHours))
		return false, nil
	}

	// check for "keep" tag in resource pool name
	matches := keepTagRegex.FindStringSubmatch(resourcePool.Name)
	if len(matches) == 3 {
		value, _ := strconv.Atoi(matches[1])
		unit := matches[2]

		var keepDuration time.Duration
		switch unit {
		case "h":
			keepDuration = time.Duration(value) * time.Hour
		case "d":
			keepDuration = time.Duration(value) * 24 * time.Hour
		}

		createDuration := now.Sub(resourcePool.CreateTime.AsTime())
		if createDuration < keepDuration {
			tilog.Info(ctx, "resource pool is within the 'keep' tag retention period, skipping deletion",
				zap.Uint64("resource_pool_id", idlePool.ResourcePoolId),
				zap.String("name", resourcePool.Name),
				zap.String("keep_tag", matches[0]),
				zap.Duration("keep_duration", keepDuration),
				zap.Duration("current_age", createDuration))
			return false, nil
		}
	}

	_, err = w.resourcePoolSvc.DeleteResourcePool(ctx, &globalngv1.DeleteResourcePoolRequest{
		ResourcePoolId: idlePool.ResourcePoolId,
	})

	if err != nil {
		tilog.Error(ctx, "failed to delete idle resource pool",
			zap.Uint64("resource_pool_id", idlePool.ResourcePoolId),
			zap.Error(err))
		return true, err
	}

	tilog.Info(ctx, "deleted idle resource pool successfully",
		zap.Uint64("resource_pool_id", idlePool.ResourcePoolId))
	return true, nil
}
