package mysql

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"

	mysqlDriver "github.com/go-sql-driver/mysql"

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
)

func contextWithCommandApp(ctx context.Context, value string) context.Context {
	if strings.TrimSpace(value) == "" {
		return appcode.WithContext(ctx, appcode.FromContext(ctx))
	}

	return appcode.WithContext(ctx, value)
}

func normalizedEntryAppCode(ctx context.Context, value string) string {
	if strings.TrimSpace(value) == "" {
		return appcode.FromContext(ctx)
	}

	return appcode.Normalize(value)
}

func checkedMul(unit int64, count int64) (int64, error) {
	if unit < 0 || count <= 0 {
		return 0, xerr.New(xerr.InvalidArgument, "amount is invalid")
	}
	if unit != 0 && count > math.MaxInt64/unit {
		return 0, xerr.New(xerr.InvalidArgument, "amount overflow")
	}
	return unit * count, nil
}

func checkedAdd(left int64, right int64) (int64, error) {
	if right < 0 || left > math.MaxInt64-right {
		return 0, xerr.New(xerr.CoinSellerStockAmountInvalid, "coin amount overflow")
	}
	return left + right, nil
}

func checkedAddDelta(left int64, right int64) (int64, error) {
	if (right > 0 && left > math.MaxInt64-right) || (right < 0 && left < math.MinInt64-right) {
		return 0, xerr.New(xerr.CoinSellerStockAmountInvalid, "coin amount overflow")
	}
	return left + right, nil
}

func stableHash(value string) string {
	sum := sha256.Sum256([]byte(value))
	return hex.EncodeToString(sum[:])
}

// boundedDerivedCommandID 为内部子动作保留可读前缀，同时保证最终键不超过所有
// command_id VARCHAR(128) 的共同边界。正常短键保持历史值，极长客户端键才稳定收敛为哈希。
func boundedDerivedCommandID(prefix string, commandID string) string {
	commandID = strings.TrimSpace(commandID)
	derived := prefix + commandID
	if len(derived) <= 128 {
		return derived
	}
	return prefix + stableHash(commandID)
}

func mustJSON(value any) string {
	body, err := json.Marshal(value)
	if err != nil {
		return "{}"
	}
	return string(body)
}

func transactionID(appCode string, commandID string) string {
	return "wtx_" + stableHash(appcode.Normalize(appCode)+"|"+commandID)
}

func coinSellerStockID(appCode string, commandID string) string {
	return "cstock_" + stableHash(appcode.Normalize(appCode)+"|"+commandID)
}

func billingReceiptID(appCode string, commandID string) string {
	return "bill_" + stableHash(appcode.Normalize(appCode)+"|"+commandID)
}

func eventID(transactionID string, eventType string, userID int64, assetType string) string {
	return "wev_" + stableHash(fmt.Sprintf("%s|%s|%d|%s", transactionID, eventType, userID, assetType))
}

func isMySQLDuplicateError(err error) bool {
	var mysqlErr *mysqlDriver.MySQLError
	return errors.As(err, &mysqlErr) && mysqlErr.Number == 1062
}
