// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package consul

import (
	"fmt"
	"strconv"

	"github.com/hashicorp/consul/agent/structs"
)

// Status endpoint is used to check on server status
type Status struct {
	server *Server
}

// Ping is used to just check for connectivity
func (s *Status) Ping(args EmptyReadRequest, reply *struct{}) error {
	return nil
}

// Leader is used to get the address of the leader
func (s *Status) Leader(args *structs.DCSpecificRequest, reply *string) error {
	// not using the regular forward function as it does a bunch of stuff we
	// dont want like verifying consistency etc. We just want to enable DC
	// forwarding
	if args.Datacenter != "" && args.Datacenter != s.server.config.Datacenter {
		return s.server.forwardDC("Status.Leader", args.Datacenter, args, reply)
	}

	leader := string(s.server.raft.Leader())
	if leader != "" {
		*reply = leader
	} else {
		*reply = ""
	}
	return nil
}

// Peers is used to get all the Raft peers
func (s *Status) Peers(args *structs.DCSpecificRequest, reply *[]string) error {
	// not using the regular forward function as it does a bunch of stuff we
	// dont want like verifying consistency etc. We just want to enable DC
	// forwarding
	if args.Datacenter != "" && args.Datacenter != s.server.config.Datacenter {
		return s.server.forwardDC("Status.Peers", args.Datacenter, args, reply)
	}

	future := s.server.raft.GetConfiguration()
	if err := future.Error(); err != nil {
		return err
	}

	for _, server := range future.Configuration().Servers {
		*reply = append(*reply, string(server.Address))
	}
	return nil
}

// EmptyReadRequest implements the interface used by middleware.RequestRecorder
// to communicate properties of requests.
type EmptyReadRequest struct{}

func (e EmptyReadRequest) IsRead() bool {
	return true
}

// RaftStats is used by Autopilot to query the raft stats of the local server.
func (s *Status) RaftStats(args EmptyReadRequest, reply *structs.RaftStats) error {
	stats := s.server.raft.Stats()

	var err error
	reply.LastContact = stats["last_contact"]
	reply.LastIndex, err = strconv.ParseUint(stats["last_log_index"], 10, 64)
	if err != nil {
		return fmt.Errorf("error parsing server's last_log_index value: %w", err)
	}
	reply.LastTerm, err = strconv.ParseUint(stats["last_log_term"], 10, 64)
	if err != nil {
		return fmt.Errorf("error parsing server's last_log_term value: %w", err)
	}

	return nil
}
