// Copyright 2022 The Fuchsia 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 botanist

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"cloud.google.com/go/storage"
)

// emptyPackageRepo is a helper that constructs an empty package repository
// with the expected structure.
func emptyPackageRepo(t *testing.T) string {
	t.Helper()
	localRepo := t.TempDir()

	repoPath := filepath.Join(localRepo, "repository")
	if err := os.Mkdir(repoPath, os.ModePerm); err != nil {
		t.Fatalf("Mkdir(%s) failed; got %s, want <nil> error", repoPath, err)
	}

	rootJSONPath := filepath.Join(repoPath, "root.json")
	f, err := os.Create(rootJSONPath)
	if err != nil {
		t.Fatalf("Create(%s) failed; got %s, want <nil> error", rootJSONPath, err)
	}
	defer f.Close()

	blobPath := filepath.Join(localRepo, "blobs")
	if err := os.Mkdir(blobPath, os.ModePerm); err != nil {
		t.Fatalf("Mkdir(%s) failed; got %s, want <nil> error", blobPath, err)
	}
	return localRepo
}

func TestPackageServer(t *testing.T) {
	testCases := []struct {
		name           string
		endpoint       string
		local          bool
		wantStatusCode int
		wantContents   string
	}{
		{
			name:           "local repository fetches work as expected",
			endpoint:       "/repository/targets.json",
			local:          true,
			wantStatusCode: http.StatusOK,
			wantContents:   "{\"targets\": []}",
		},
		{
			name:           "local blob fetches work as expected",
			endpoint:       "/blobs/123456",
			local:          true,
			wantStatusCode: http.StatusOK,
			wantContents:   "desired contents",
		},
		{
			name:           "remote repository fetches work as expected",
			endpoint:       "/repository/targets.json",
			wantStatusCode: http.StatusOK,
			wantContents:   "{\"targets\": []}",
		},
		{
			name:           "remote blob fetches work as expected",
			endpoint:       "/blobs/123456",
			wantStatusCode: http.StatusOK,
			wantContents:   "desired contents",
		},
		{
			name:           "remote fetch of non-existent object returns not found",
			endpoint:       "/blobs/123456",
			wantStatusCode: http.StatusNotFound,
		},
		{
			name:           "remote fetch of invalid path returns bad request",
			endpoint:       "/invalid",
			wantStatusCode: http.StatusBadRequest,
		},
	}
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()

			// Set up the local package repository.
			localRepo := emptyPackageRepo(t)

			// Override the GCS reader to effectively return a 404 unless the
			// test case overrides it below.
			getGCSReader = func(_ context.Context, _ *storage.Client, _, _ string) (io.ReadCloser, int, error) {
				return nil, 0, storage.ErrObjectNotExist
			}

			// Add any contents to the repo (both locally and in the "remote")
			// that the test case requires.
			if tc.wantContents != "" {
				if tc.local {
					localPath := filepath.Join(localRepo, tc.endpoint)
					if err := os.WriteFile(localPath, []byte(tc.wantContents), os.ModePerm); err != nil {
						t.Fatalf("WriteFile(%s, %s) failed; got %s, want <nil> error", localPath, tc.wantContents, err)
					}
				} else {
					getGCSReader = func(_ context.Context, _ *storage.Client, _, _ string) (io.ReadCloser, int, error) {
						r := strings.NewReader(tc.wantContents)
						return io.NopCloser(r), len(tc.wantContents), nil
					}
				}
			}

			// Start the package server.
			// We ignore the returned repoURL and blobURL to make testing
			// invalid endpoints easier.
			pkgSrv, err := NewPackageServer(ctx, localRepo, "", "", "", 8080)
			if err != nil {
				t.Fatalf("NewPackageServer failed; got %s, want <nil> error", err)
			}
			defer pkgSrv.Close()

			// Make a request to the endpoint and validate that we get the
			// expected response.
			addr := fmt.Sprintf("http://%s:8080%s", localhostPlaceholder, tc.endpoint)
			res, err := http.Get(addr)
			if err != nil {
				t.Fatalf("http.Get(%s) failed; got %s, want <nil> error", addr, err)
			}
			defer res.Body.Close()

			if res.StatusCode != tc.wantStatusCode {
				t.Errorf("got incorrect status code; got %d, want %d", res.StatusCode, tc.wantStatusCode)
			}
			if tc.wantContents != "" {
				body, err := io.ReadAll(res.Body)
				if err != nil {
					t.Fatalf("reading response body failed; got %s, want <nil> error", err)
				}
				if tc.wantContents != string(body) {
					t.Errorf("got incorrect contents; got %q, want %q", string(body), tc.wantContents)
				}
			}
		})
	}
}
