package adapterimpl

import (
	"encoding/json"
	"strings"

	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

type sys9ErrorResponse struct {
	Code    string `json:"code"`
	Error   string `json:"error"`
	Message string `json:"message"`
}

func mapSys9Error(statusCode int, body []byte) error {
	if statusCode == 401 {
		return bizerr.New(bizerr.ErrCodeAuth, "sys9 auth failed")
	}
	if statusCode == 403 {
		return bizerr.New(bizerr.ErrCodePermission, "sys9 permission denied")
	}
	if statusCode == 429 {
		return bizerr.New(bizerr.ErrCodeTooManyRequests, "sys9 too many requests")
	}
	if statusCode == 504 {
		return bizerr.New(bizerr.ErrCodeTimeout, "sys9 request timeout")
	}

	code := ""
	msg := ""
	var e sys9ErrorResponse
	if len(body) > 0 && json.Unmarshal(body, &e) == nil {
		code = strings.ToUpper(strings.TrimSpace(firstNonEmpty(e.Code, e.Error)))
		msg = strings.TrimSpace(e.Message)
	}

	switch code {
	case "CHALLENGE_INVALID", "CHALLENGE_REPLAYED", "INVALID_PROOF", "ENTITY_BOUNDARY_VIOLATION", "ANCHOR_MISMATCH":
		return bizerr.New(bizerr.ErrCodeAuth, "sys9 auth rejected: %s %s", code, msg)
	case "SERVICE_UNAVAILABLE", "CONTROL_PLANE_READ_ONLY", "RATE_LIMITED":
		return bizerr.New(bizerr.ErrCodeTimeout, "sys9 temporary unavailable: %s %s", code, msg)
	case "COMMIT_OUTCOME_UNKNOWN":
		return bizerr.New(bizerr.ErrCodeTimeout, "sys9 commit outcome unknown: %s %s", code, msg)
	default:
		if statusCode >= 400 && statusCode < 500 {
			return bizerr.New(bizerr.ErrCodeParams, "sys9 request rejected: %s %s", code, msg)
		}
		if statusCode >= 500 {
			return bizerr.New(bizerr.ErrCodeUnknown, "sys9 internal error: %s %s", code, msg)
		}
		return bizerr.New(bizerr.ErrCodeUnknown, "sys9 request failed")
	}
}

func firstNonEmpty(values ...string) string {
	for _, v := range values {
		if strings.TrimSpace(v) != "" {
			return v
		}
	}
	return ""
}
