package pb

import (
	"context"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// Workload registry messages. Hand-written like the rest of this package: the
// .proto is the contract, this file is the Go side of it, and the two must be
// changed together. The agent module carries the same declarations.

// Workload is one container or one systemd unit.
type Workload struct {
	Kind      string   `json:"kind"`
	Id        string   `json:"id"`
	Name      string   `json:"name"`
	State     string   `json:"state"`
	Health    string   `json:"health,omitempty"`
	Image     string   `json:"image,omitempty"`
	Stack     string   `json:"stack,omitempty"`
	Ports     []string `json:"ports,omitempty"`
	Restarts  int32    `json:"restarts,omitempty"`
	StartedAt string   `json:"started_at,omitempty"` // RFC3339, empty when not running
	Protected bool     `json:"protected,omitempty"`
}

// ReportWorkloadsRequest carries what a server is running.
//
// Offer-then-send, the same handshake as ReportPackages: the agent calls once
// with Workloads empty, and resends with the body only if NeedFull is set.
type ReportWorkloadsRequest struct {
	ServerId     string     `json:"server_id"`
	AgentToken   string     `json:"agent_token"`
	Hash         string     `json:"hash"`
	DockerOk     bool       `json:"docker_ok"`
	DockerError  string     `json:"docker_error,omitempty"`
	SystemdOk    bool       `json:"systemd_ok"`
	SystemdError string     `json:"systemd_error,omitempty"`
	Workloads    []Workload `json:"workloads,omitempty"` // empty on the offer call
	// Full marks the second call. It is not inferred from an empty Workloads
	// slice: a host running nothing sends an empty list as its full report.
	Full bool `json:"full,omitempty"`
}

type ReportWorkloadsResponse struct {
	NeedFull bool `json:"need_full"`
}

// RefreshWorkloadsCmd carries no payload back. It makes the agent report
// immediately through ReportWorkloads, so there is exactly one writer for the
// server_workloads collection rather than two arriving by different routes.
type RefreshWorkloadsCmd struct{}

type ControlWorkloadCmd struct {
	Kind   string `json:"kind"`
	Id     string `json:"id"`
	Action string `json:"action"` // start | stop | restart
}

type WorkloadLogsCmd struct {
	Kind string `json:"kind"`
	Id   string `json:"id"`
	Tail int32  `json:"tail,omitempty"`
}

type WorkloadLogsResult struct {
	CommandId string `json:"command_id"`
	Text      string `json:"text,omitempty"`
	Truncated bool   `json:"truncated,omitempty"`
	Error     string `json:"error,omitempty"`
}

func (UnimplementedVantageServer) ReportWorkloads(context.Context, *ReportWorkloadsRequest) (*ReportWorkloadsResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ReportWorkloads not implemented")
}

func (c *keyManagerClient) ReportWorkloads(ctx context.Context, in *ReportWorkloadsRequest, opts ...grpc.CallOption) (*ReportWorkloadsResponse, error) {
	out := new(ReportWorkloadsResponse)
	if err := c.cc.Invoke(ctx, "/vantage.v1.Vantage/ReportWorkloads", in, out, opts...); err != nil {
		return nil, err
	}
	return out, nil
}

func _Vantage_ReportWorkloads_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ReportWorkloadsRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(VantageServer).ReportWorkloads(ctx, in)
	}
	info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/vantage.v1.Vantage/ReportWorkloads"}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(VantageServer).ReportWorkloads(ctx, req.(*ReportWorkloadsRequest))
	}
	return interceptor(ctx, in, info, handler)
}
