package service

import (
	"errors"
	"regexp"
	"strings"

	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/engine"
)

const maxAthenaFailureReasonRunes = 1024

var (
	athenaFailureARNPattern = regexp.MustCompile(`(?i)\barn:aws[a-z0-9-]*:[^\s"'<>]+`)
	athenaFailureURLPattern = regexp.MustCompile(`(?i)\b(?:s3|https?)://[^\s"'<>]+`)
)

type athenaFailureDiagnostics struct {
	QueryID      string
	State        string
	Reason       string
	Category     int32
	Type         int32
	Retryable    bool
	WasTruncated bool
}

func athenaQueryFailureLogFields(err error, clusterID string) []zap.Field {
	diagnostics, ok := athenaQueryFailureDiagnostics(err, clusterID)
	if !ok {
		return nil
	}
	return []zap.Field{
		zap.String("athena_query_id", diagnostics.QueryID),
		zap.String("athena_state", diagnostics.State),
		zap.String("athena_state_change_reason", diagnostics.Reason),
		zap.Bool("athena_reason_truncated", diagnostics.WasTruncated),
		zap.Int32("athena_error_category", diagnostics.Category),
		zap.Int32("athena_error_type", diagnostics.Type),
		zap.Bool("athena_retryable", diagnostics.Retryable),
	}
}

func athenaQueryFailureDiagnostics(err error, clusterID string) (athenaFailureDiagnostics, bool) {
	var queryErr *engine.AthenaQueryError
	if !errors.As(err, &queryErr) || queryErr == nil {
		return athenaFailureDiagnostics{}, false
	}

	reason, truncated := sanitizeAthenaFailureReason(queryErr.Reason, clusterID)
	return athenaFailureDiagnostics{
		QueryID:      queryErr.QueryID,
		State:        string(queryErr.State),
		Reason:       reason,
		Category:     queryErr.ErrorCategory,
		Type:         queryErr.ErrorType,
		Retryable:    queryErr.Retryable,
		WasTruncated: truncated,
	}, true
}

func sanitizeAthenaFailureReason(reason, clusterID string) (string, bool) {
	reason = strings.Map(func(r rune) rune {
		if r < 0x20 || r == 0x7f {
			return ' '
		}
		return r
	}, reason)
	reason = strings.Join(strings.Fields(reason), " ")
	reason = athenaFailureARNPattern.ReplaceAllString(reason, "[redacted-aws-arn]")
	reason = athenaFailureURLPattern.ReplaceAllString(reason, "[redacted-location]")
	if clusterID != "" {
		reason = strings.ReplaceAll(reason, clusterID, "[redacted-cluster]")
	}

	runes := []rune(reason)
	if len(runes) <= maxAthenaFailureReasonRunes {
		return reason, false
	}
	return string(runes[:maxAthenaFailureReasonRunes]), true
}
