package export

import (
	"fmt"
	"regexp"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/equality"
)

const (
	DumpFailMessageTemplate      = "dump failed:"
	SQLFailMessageTemplate       = "sql:"
	AccessDeniedMessageTemplate  = "AccessDenied:"
	PartitionFailMessageTemplate = "partition:"
)

// Export error messages
const (
	unknownErrorMessage               = "Export failed with unknown error. Please retry later or contact us for support."
	ExecuteSQLErrorMessage            = "Execute SQL error."
	S3RoleArnAccessDeniedMessage      = "AccessDenied. Please check your S3 role arn or contact us for support."
	S3AccessKeyAccessDeniedMessage    = "AccessDenied. Please check your S3 access key or contact us for support."
	OSSAccessKeyAccessDeniedMessage   = "AccessDenied. Please check your OSS AccessKey pair or contact us for support."
	GCSAccessKeyAccessDeniedMessage   = "AccessDenied. Please check your GCS credential or contact us for support."
	AzureAccessKeyAccessDeniedMessage = "AccessDenied. Please check your Azure account key or contact us for support."
	PartitionErrorMessage             = "Partition error."
)

const (
	ExportConfigCM = "export-config"

	cpuResourceLimitKey             = "cpu-resource-limit"
	cpuResourceRequestKey           = "cpu-resource-request"
	memoryResourceLimitKey          = "mem-resource-limit"
	memoryResourceRequestKey        = "mem-resource-request"
	memoryResourceLimitParquetKey   = "mem-resource-limit-parquet"
	memoryResourceRequestParquetKey = "mem-resource-request-parquet"
	dumplingConcurrencyKey          = "dumpling-concurrency"
	nodeSelector                    = "node-selector"
	tolerations                     = "tolerations"

	vipCpuResourceLimitKey             = "vip-cpu-resource-limit"
	vipCpuResourceRequestKey           = "vip-cpu-resource-request"
	vipMemoryResourceLimitKey          = "vip-mem-resource-limit"
	vipMemoryResourceRequestKey        = "vip-mem-resource-request"
	vipMemoryResourceLimitParquetKey   = "vip-mem-resource-limit-parquet"
	vipMemoryResourceRequestParquetKey = "vip-mem-resource-request-parquet"
	vipDumplingConcurrencyKey          = "vip-dumpling-concurrency"
	vipNodeSelector                    = "vip-node-selector"
	vipTolerations                     = "vip-tolerations"

	superVipCpuResourceLimitKey      = "super-vip-cpu-resource-limit"
	superVipCpuResourceRequestKey    = "super-vip-cpu-resource-request"
	superVipMemoryResourceLimitKey   = "super-vip-mem-resource-limit"
	superVipMemoryResourceRequestKey = "super-vip-mem-resource-request"
	superVipDumplingConcurrencyKey   = "super-vip-dumpling-concurrency"
	superVipNodeSelector             = "super-vip-node-selector"
	superVipTolerations              = "super-vip-tolerations"
	superVipWhiteList                = "super-vip-white-list"
	enableNewResourceGroupName       = "enable-export-new-resource-group"
	assignTiDBMaxWaitKey             = "assign-tidb-max-wait"

	vipTidbPool       = "vip-tidb-pool"
	canaryVipTidbPool = "canary-vip-tidb-pool"
	superVipTidbPool  = "super-vip-tidb-pool"
)

type ExportType string

const (
	ExportTypeDefault  ExportType = "default"
	ExportTypeVIP      ExportType = "vip"
	ExportTypeSuperVIP ExportType = "super-vip"
)

func (r *reconcileContext) updateProgress(phase cloudv1.ExportPhase, reason string) (bool, error) {
	if r.export.Status.Phase == phase && r.export.Status.Message == reason {
		return false, nil
	}

	r.InfraRecorder.Event(r.export, corev1.EventTypeNormal, string(phase), reason)

	action, err := r.ensureStatus(func(
		status *cloudv1.ExportStatus,
	) error {
		status.Phase = phase
		status.Message = reason
		return nil
	})
	if err != nil {
		return false, fmt.Errorf("update progress err: %w", err)
	}
	return action, nil
}

// ensureStatus update the export status if necessary.
func (r *reconcileContext) ensureStatus(mutateFn func(
	exportStatus *cloudv1.ExportStatus,
) error) (bool, error) {
	old := r.export.Status.DeepCopy()
	if err := mutateFn(&r.export.Status); err != nil {
		return false, err
	}
	if equality.Semantic.DeepEqual(old, &r.export.Status) {
		// no changed, skip updating
		// Note: the local status may not be same as the truth,
		// but we will reach eventually-consistency via reconciliation
		return false, nil
	}

	return true, r.InfraClient.Status().Update(r.ctx, r.export)
}

func extractExportSize(msg string) (string, string, error) {
	// Example message likes: [FinishedSize]: 12345.00\n[CompressedSize]: 6789.00\n
	re := regexp.MustCompile(`\[FinishedSize\]: ([^\n]+)\n\[CompressedSize\]: ([^\n]+)`)
	matches := re.FindStringSubmatch(msg)

	if len(matches) != 3 {
		return "", "", fmt.Errorf("failed to extract size information from message: %s", msg)
	}

	finishedSizeStr := matches[1]
	compressedSizeStr := matches[2]

	if compressedSizeStr == "0.00" {
		compressedSizeStr = finishedSizeStr
	}

	return finishedSizeStr, compressedSizeStr, nil
}
