// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sign

import (
	"context"
	"fmt"
	"io"
	"log"
	"sync"
	"testing"
	"time"

	"github.com/google/uuid"
	"golang.org/x/build/internal/access"
	"golang.org/x/build/internal/relui/protos"
	"golang.org/x/net/nettest"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
)

func TestUpdateSigningStatus(t *testing.T) {
	ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())
	client, server := setupSigningTest(t, ctx)
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	go fakeSigningServerClient(t, ctx, client)
	wg := &sync.WaitGroup{}
	wg.Add(3)
	go signRequestSeries(t, ctx, "request-1", server, BuildGPG, wg)
	go signRequestSeries(t, ctx, "request-2", server, BuildMacOS, wg)
	go signRequestSeries(t, ctx, "request-3", server, BuildWindows, wg)
	wg.Wait()
}

func TestUpdateSigningStatusError(t *testing.T) {
	t.Run("unauthenticated client", func(t *testing.T) {
		ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())
		client, _ := setupSigningTest(t, ctx)
		stream, err := client.UpdateSigningStatus(context.Background())
		if err != nil {
			t.Fatalf("client.UpdateSigningStatus(ctx) = %v,  %s; want no error", stream, err)
		}
		wantCode := codes.Unauthenticated
		if _, err = stream.Recv(); status.Code(err) != wantCode {
			t.Fatalf("stream.Recv() = %s, want %s", status.Code(err), wantCode)
		}
	})
	t.Run("non-existent signing request", func(t *testing.T) {
		// skipping due to go.dev/issue/54654
		t.Skip("skipping flaky test. see go.dev/issue/54654")

		ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())
		client, server := setupSigningTest(t, ctx)
		ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
		defer cancel()
		go fakeSigningServerClient(t, ctx, client)
		if _, _, _, err := server.ArtifactSigningStatus(ctx, "not-exist"); err == nil {
			t.Fatalf("ArtifactSigningStatus(ctx, %q) = _, _, nil; want error", "not-exist")
		}
	})
}

func signRequestSeries(t *testing.T, ctx context.Context, id string, server *SigningServer, buildT BuildType, wg *sync.WaitGroup) {
	defer wg.Done()
	const uri = "gs://foo/bar.tar.gz"
	jobID, err := server.SignArtifact(ctx, buildT, []string{uri})
	if err != nil {
		t.Fatalf("SignArtifact(ctx, %q, %v, %q = %s; want no error", id, buildT, uri, err)
	}
	_, _, _, err = server.ArtifactSigningStatus(ctx, jobID)
	if err != nil {
		t.Fatalf("ArtifactSigningStatus(%q) = %s; want no error", id, err)
	}
	_, _, _, err = server.ArtifactSigningStatus(ctx, jobID)
	if err != nil {
		t.Fatalf("ArtifactSigningStatus(%q) = %s; want no error", id, err)
	}
}

// fakeSigningServerClient is a simple implementation of how we expect the client side to perform.
// A signing request initiates a signing job. The first status update should return a status of
// running. The second status request will return a status of Completed.
func fakeSigningServerClient(t *testing.T, ctx context.Context, client protos.ReleaseServiceClient) {
	stream, err := client.UpdateSigningStatus(ctx)
	if err != nil {
		t.Fatalf("client.UpdateSigningStatus(ctx) = %v,  %s; want no error", stream, err)
	}
	requests := make(chan *protos.SigningRequest, 10)
	go func() {
		defer close(requests)
		for {
			in, err := stream.Recv()
			if err == io.EOF {
				return
			}
			if err != nil && status.Code(err) == codes.Canceled {
				return
			}
			if err != nil {
				t.Logf("client.stream.Recv() = nil, %s; want no error", err)
				return
			}
			requests <- in
		}
	}()
	jobs := make(map[string]int) // jobID -> request count
	for request := range requests {
		resp := &protos.SigningStatus{
			MessageId:   request.GetMessageId(),
			StatusOneof: nil,
		}
		switch r := request.RequestOneof.(type) {
		case *protos.SigningRequest_Sign:
			newJob := uuid.NewString() // Create a new pretend job with an ID.
			jobs[newJob] = 1
			resp.StatusOneof = &protos.SigningStatus_Started{
				Started: &protos.StatusStarted{
					JobId: newJob,
				},
			}
		case *protos.SigningRequest_Status:
			id := r.Status.JobId
			c, ok := jobs[id]
			if !ok {
				resp.StatusOneof = &protos.SigningStatus_NotFound{}
			} else if c == 1 {
				jobs[id] = 2
				resp.StatusOneof = &protos.SigningStatus_Running{}
			} else if c == 2 {
				delete(jobs, id)
				resp.StatusOneof = &protos.SigningStatus_Completed{
					Completed: &protos.StatusCompleted{
						GcsUri: []string{"gs://private-bucket/some-file.tar.gz"},
					},
				}
			}
		}
		if err := stream.Send(resp); err != nil {
			log.Fatalf("client.stream.Send(%v) = %s, want no error", resp, err)
		}
	}
	stream.CloseSend()
}

func setupSigningTest(t *testing.T, ctx context.Context) (protos.ReleaseServiceClient, *SigningServer) {
	lis, err := nettest.NewLocalListener("tcp")
	if err != nil {
		t.Fatalf("nettest.NewLocalListener(\"tcp\") =  %s; want no error", err)
	}
	sopts := access.FakeIAPAuthInterceptorOptions()
	s := grpc.NewServer(sopts...)
	ss := NewServer()
	protos.RegisterReleaseServiceServer(s, ss)
	go s.Serve(lis)
	// create GRPC client
	copts := []grpc.DialOption{
		grpc.WithBlock(),
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	}
	ctx, cancel := context.WithTimeout(ctx, time.Second)
	defer cancel()
	conn, err := grpc.DialContext(ctx, lis.Addr().String(), copts...)
	if err != nil {
		lis.Close()
		t.Fatalf("grpc.Dial(%s, %+v) = nil, %s; want no error", lis.Addr().String(), copts, err)
	}
	sc := protos.NewReleaseServiceClient(conn)
	t.Cleanup(func() {
		conn.Close()
		s.Stop()
		lis.Close()
	})
	return sc, ss
}

func fakeAuthContext(ctx context.Context) context.Context {
	return access.ContextWithIAP(ctx, access.IAPFields{
		Email: "accounts.google.com:relui-user@google.com",
		ID:    "accounts.google.com:randomuuidstuff",
	})
}

func fakeIAP() access.IAPFields {
	return fakeIAPWithUser("example", "randomuuidstuff")
}

func fakeIAPWithUser(user string, id string) access.IAPFields {
	return access.IAPFields{
		Email: fmt.Sprintf("accounts.google.com:%s@gmail.com", user),
		ID:    fmt.Sprintf("accounts.google.com:%s", id),
	}
}
