// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package supervisor

import (
	"context"
	"sync"
	"time"

	"golang.org/x/xerrors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	"github.com/gitpod-io/gitpod/common-go/util"
	"github.com/gitpod-io/gitpod/supervisor/api"
)

type SupervisorClient struct {
	conn      *grpc.ClientConn
	closeOnce sync.Once

	Status   api.StatusServiceClient
	Terminal api.TerminalServiceClient
	Info     api.InfoServiceClient
}

type SupervisorClientOption struct {
	Address string
}

func New(ctx context.Context, options ...SupervisorClientOption) (*SupervisorClient, error) {
	address := util.GetSupervisorAddress()
	for _, option := range options {
		if option.Address != "" {
			address = option.Address
		}
	}
	conn, err := grpc.DialContext(ctx, address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		return nil, xerrors.Errorf("failed connecting to supervisor: %w", err)
	}

	return &SupervisorClient{
		conn:     conn,
		Status:   api.NewStatusServiceClient(conn),
		Terminal: api.NewTerminalServiceClient(conn),
		Info:     api.NewInfoServiceClient(conn),
	}, nil
}

func (client *SupervisorClient) Close() {
	client.closeOnce.Do(func() {
		client.conn.Close()
	})
}

func (client *SupervisorClient) WaitForIDEReady(ctx context.Context) {
	var ideReady bool
	for !ideReady {
		resp, _ := client.Status.IDEStatus(ctx, &api.IDEStatusRequest{Wait: true})
		if resp != nil {
			ideReady = resp.Ok
		}
		if ctx.Err() != nil {
			return
		}
		if !ideReady {
			time.Sleep(1 * time.Second)
		}
	}
}
