package dm

import (
	"encoding/json"
	"strings"

	dmpb "github.com/tidbcloud/dataflow-service/idl/pbgen/proto/dm"
	"go.uber.org/zap"
)

const (
	unknownErrMsg = "This is an unknown error."
	contactMsg    = "Please contact support team."
)

func genUnknownError(logger *zap.Logger) *dmpb.ProcessError {
	logger.Warn(unknownErrMsg)
	return &dmpb.ProcessError{
		Message:    unknownErrMsg,
		Workaround: contactMsg,
	}
}

func isProcessErrEmpty(err *dmpb.ProcessError) bool {
	if err == nil {
		return true
	}
	if err.ErrCode == 0 && len(err.Message) == 0 && len(err.Workaround) == 0 {
		return true
	}
	return false
}

func genErrorWithSupport(logger *zap.Logger, message *string) *dmpb.ProcessError {
	if message != nil && *message != "" {
		return &dmpb.ProcessError{
			Message:    *message,
			Workaround: contactMsg,
		}
	}
	return genUnknownError(logger)
}

func genProcessErrorFromDFJobError(logger *zap.Logger, raw string) *dmpb.ProcessError {
	msg, workaround := extractDFJobError(raw)
	msg = normalizeErrMsg(msg, "")
	if msg == "" {
		return genUnknownError(logger)
	}
	if workaround == "" {
		workaround = contactMsg
	}
	return &dmpb.ProcessError{
		Message:    msg,
		Workaround: workaround,
	}
}

func extractDFJobError(raw string) (string, string) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return "", ""
	}

	if body, ok := extractDMProxyErrorBody(raw); ok {
		trimmedErrMsg := strings.TrimSpace(body.ErrorMsg)
		if msg, workaround := extractMessageAndWorkaround(trimmedErrMsg); msg != "" {
			return msg, workaround
		}
		if trimmedErrMsg != "" {
			return trimmedErrMsg, ""
		}
	}

	return extractMessageAndWorkaround(raw)
}

type dmProxyErrorBody struct {
	ErrorMsg string `json:"error_msg"`
}

func extractDMProxyErrorBody(raw string) (*dmProxyErrorBody, bool) {
	idx := strings.Index(raw, "response_body:")
	if idx == -1 {
		return nil, false
	}

	body := strings.TrimSpace(raw[idx+len("response_body:"):])
	if body == "" {
		return nil, false
	}

	resp := &dmProxyErrorBody{}
	if err := json.Unmarshal([]byte(body), resp); err != nil {
		return nil, false
	}
	return resp, true
}

func extractMessageAndWorkaround(raw string) (string, string) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return "", ""
	}

	msg := raw
	workaround := ""

	if idx := strings.Index(msg, "Message: "); idx != -1 {
		msg = strings.TrimSpace(msg[idx+len("Message: "):])
	}
	if idx := strings.Index(msg, ", Workaround: "); idx != -1 {
		workaround = strings.TrimSpace(msg[idx+len(", Workaround: "):])
		msg = strings.TrimSpace(msg[:idx])
	}

	return msg, workaround
}
