package slashing

import (
	sdk "github.com/cosmos/cosmos-sdk/types"
)

func NewHandler(k Keeper) sdk.Handler {
	return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
		// NOTE msg already has validate basic run
		switch msg := msg.(type) {
		case MsgUnjail:
			return handleMsgUnjail(ctx, msg, k)
		default:
			return sdk.ErrTxDecode("invalid message parse in staking module").Result()
		}
	}
}

// Validators must submit a transaction to unjail itself after
// having been jailed (and thus unbonded) for downtime
func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {

	// Validator must exist
	validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr)
	if validator == nil {
		return ErrNoValidatorForAddress(k.codespace).Result()
	}

	if !validator.GetJailed() {
		return ErrValidatorNotJailed(k.codespace).Result()
	}

	addr := sdk.ValAddress(validator.GetPubKey().Address())

	// Signing info must exist
	info, found := k.getValidatorSigningInfo(ctx, addr)
	if !found {
		return ErrNoValidatorForAddress(k.codespace).Result()
	}

	// Cannot be unjailed until out of jail
	if ctx.BlockHeader().Time.Before(info.JailedUntil) {
		return ErrValidatorJailed(k.codespace).Result()
	}

	// Update the starting height (so the validator can't be immediately jailed again)
	info.StartHeight = ctx.BlockHeight()
	k.setValidatorSigningInfo(ctx, addr, info)

	// Unjail the validator
	k.validatorSet.Unjail(ctx, validator.GetPubKey())

	tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String()))

	return sdk.Result{
		Tags: tags,
	}
}
