package premium_dm

import (
	stderrors "errors"
	"strings"

	"github.com/pingcap/tiflow/dm/pkg/checker"
	"github.com/tidbcloud/dataflow-service-ng/app/repo/entity"
	"github.com/tidbcloud/dataflow-service-ng/pkg/agent"
)

const (
	premiumDMPrecheckInitializeCheckerText = "fail to initialize checker"
	premiumDMPrecheckExecutionFailedText   = "precheck execution failed"
	premiumDMPrecheckMessageLabel          = "Message:"
	premiumDMPrecheckWorkaroundLabel       = ", Workaround:"

	// premiumDMPrecheckInitializationDesc is a wire marker produced by
	// dataflow-agent-ng for initialization failures encoded in CheckResults.
	premiumDMPrecheckInitializationDesc = "precheck initialization"
)

type premiumDMPrecheckUserMessage struct {
	Reason   string
	Solution string
}

func PremiumDMPrecheckInitializationDescForAPI() string {
	return premiumDMPrecheckInitializationDesc
}

func premiumDMPrecheckErrorMessage(err error) (string, bool) {
	if err == nil {
		return "", false
	}
	var agentErr *agent.ErrorResponse
	if stderrors.As(err, &agentErr) && strings.TrimSpace(agentErr.Message) != "" {
		return strings.TrimSpace(agentErr.Message), true
	}
	return strings.TrimSpace(err.Error()), false
}

func extractPremiumDMPrecheckUserError(err error) (string, bool) {
	msg, fromAgent := premiumDMPrecheckErrorMessage(err)
	if msg == "" {
		return "", false
	}

	lowerMsg := strings.ToLower(msg)
	for _, marker := range []string{
		premiumDMPrecheckInitializeCheckerText,
		premiumDMPrecheckExecutionFailedText,
	} {
		if strings.HasPrefix(lowerMsg, marker) {
			return msg, true
		}
		if fromAgent {
			idx := strings.Index(lowerMsg, marker)
			if idx >= 0 {
				return strings.TrimSpace(msg[idx:]), true
			}
		}
	}
	return "", false
}

func buildPremiumDMPrecheckFailureResults(desc, reason, solution string) entity.PremiumResults {
	result := &checker.Result{
		Desc:  desc,
		State: checker.StateFailure,
		Errors: []*checker.Error{
			{
				Severity: checker.StateFailure,
				ShortErr: reason,
			},
		},
	}
	if strings.TrimSpace(solution) != "" {
		result.Instruction = strings.TrimSpace(solution)
	}
	return entity.PremiumResults{
		Results: []*checker.Result{result},
	}
}

func extractPremiumDMPrecheckUserErrorFromResults(results *entity.PremiumResults) (string, bool) {
	message, ok := extractPremiumDMPrecheckUserMessageFromResults(results)
	if !ok {
		return "", false
	}
	return message.Reason, true
}

func extractPremiumDMPrecheckUserMessageFromResults(
	results *entity.PremiumResults,
) (*premiumDMPrecheckUserMessage, bool) {
	if results == nil {
		return nil, false
	}
	for _, result := range results.Results {
		if result == nil || result.State != checker.StateFailure {
			continue
		}
		for _, itemErr := range result.Errors {
			if itemErr == nil || strings.TrimSpace(itemErr.ShortErr) == "" {
				continue
			}
			message, ok := extractPremiumDMPrecheckResultShortError(
				strings.TrimSpace(itemErr.ShortErr),
				result.Desc == premiumDMPrecheckInitializationDesc,
			)
			if ok {
				if message.Solution == "" && strings.TrimSpace(result.Instruction) != "" {
					message.Solution = strings.TrimSpace(result.Instruction)
				}
				return message, true
			}
		}
	}
	return nil, false
}

func normalizePremiumDMPrecheckUserErrorResults(results *entity.PremiumResults) {
	if results == nil {
		return
	}
	message, ok := extractPremiumDMPrecheckUserMessageFromResults(results)
	if !ok {
		return
	}
	for _, result := range results.Results {
		if result == nil || result.State != checker.StateFailure {
			continue
		}
		for _, itemErr := range result.Errors {
			if itemErr == nil || strings.TrimSpace(itemErr.ShortErr) == "" {
				continue
			}
			itemErr.ShortErr = message.Reason
		}
		if message.Solution != "" {
			result.Instruction = message.Solution
		}
	}
}

func extractPremiumDMPrecheckResultShortError(
	shortErr string,
	allowStructuredMessage bool,
) (*premiumDMPrecheckUserMessage, bool) {
	if allowStructuredMessage {
		if message, ok := parsePremiumDMPrecheckStructuredMessage(shortErr); ok {
			return message, true
		}
	}

	reason, ok := extractPremiumDMPrecheckUserError(stderrors.New(shortErr))
	if ok {
		return &premiumDMPrecheckUserMessage{Reason: reason}, true
	}

	lowerErr := strings.ToLower(shortErr)
	for _, marker := range []string{
		premiumDMPrecheckInitializeCheckerText,
		premiumDMPrecheckExecutionFailedText,
	} {
		idx := strings.Index(lowerErr, marker)
		if idx < 0 {
			continue
		}
		return &premiumDMPrecheckUserMessage{
			Reason: strings.TrimSpace(shortErr[idx:]),
		}, true
	}
	return nil, false
}

func parsePremiumDMPrecheckStructuredMessage(shortErr string) (*premiumDMPrecheckUserMessage, bool) {
	messageIdx := strings.Index(shortErr, premiumDMPrecheckMessageLabel)
	if messageIdx < 0 {
		return nil, false
	}

	messageStart := messageIdx + len(premiumDMPrecheckMessageLabel)
	messageTail := strings.TrimSpace(shortErr[messageStart:])
	workaroundIdx := strings.Index(messageTail, premiumDMPrecheckWorkaroundLabel)
	if workaroundIdx < 0 {
		return &premiumDMPrecheckUserMessage{Reason: messageTail}, true
	}

	reason := strings.TrimSpace(messageTail[:workaroundIdx])
	solution := strings.TrimSpace(messageTail[workaroundIdx+len(premiumDMPrecheckWorkaroundLabel):])
	return &premiumDMPrecheckUserMessage{
		Reason:   reason,
		Solution: solution,
	}, true
}
