package redis

import (
	
	
	
	
)

type Scripter interface {
	Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
	EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
	EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
	EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
	ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
	ScriptLoad(ctx context.Context, script string) *StringCmd
}

var (
	_ Scripter = (*Client)(nil)
	_ Scripter = (*Ring)(nil)
	_ Scripter = (*ClusterClient)(nil)
)

type Script struct {
	src, hash string
}

func ( string) *Script {
	 := sha1.New()
	_, _ = io.WriteString(, )
	return &Script{
		src:  ,
		hash: hex.EncodeToString(.Sum(nil)),
	}
}

func ( *Script) () string {
	return .hash
}

func ( *Script) ( context.Context,  Scripter) *StringCmd {
	return .ScriptLoad(, .src)
}

func ( *Script) ( context.Context,  Scripter) *BoolSliceCmd {
	return .ScriptExists(, .hash)
}

func ( *Script) ( context.Context,  Scripter,  []string,  ...interface{}) *Cmd {
	return .Eval(, .src, , ...)
}

func ( *Script) ( context.Context,  Scripter,  []string,  ...interface{}) *Cmd {
	return .EvalRO(, .src, , ...)
}

func ( *Script) ( context.Context,  Scripter,  []string,  ...interface{}) *Cmd {
	return .EvalSha(, .hash, , ...)
}

func ( *Script) ( context.Context,  Scripter,  []string,  ...interface{}) *Cmd {
	return .EvalShaRO(, .hash, , ...)
}

// Run optimistically uses EVALSHA to run the script. If script does not exist
// it is retried using EVAL.
func ( *Script) ( context.Context,  Scripter,  []string,  ...interface{}) *Cmd {
	 := .EvalSha(, , , ...)
	if HasErrorPrefix(.Err(), "NOSCRIPT") {
		return .Eval(, , , ...)
	}
	return 
}

// RunRO optimistically uses EVALSHA_RO to run the script. If script does not exist
// it is retried using EVAL_RO.
func ( *Script) ( context.Context,  Scripter,  []string,  ...interface{}) *Cmd {
	 := .EvalShaRO(, , , ...)
	if HasErrorPrefix(.Err(), "NOSCRIPT") {
		return .EvalRO(, , , ...)
	}
	return 
}