// Copyright 2019 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 postgres

import (
	"context"
	"database/sql"
	"errors"
	"sort"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/pkgsite/internal/database"
	"golang.org/x/pkgsite/internal/derrors"
	"golang.org/x/pkgsite/internal/testing/sample"
	"golang.org/x/pkgsite/internal/version"
)

func TestDeleteModule(t *testing.T) {
	t.Parallel()
	testDB, release := acquire(t)
	defer release()
	ctx := context.Background()

	v := sample.DefaultModule()

	testDB.MustInsertModule(t, v)
	if _, err := testDB.GetModuleInfo(ctx, v.ModulePath, v.Version); err != nil {
		t.Fatal(err)
	}

	vm := sample.DefaultVersionMap()
	if err := testDB.UpsertVersionMap(ctx, vm); err != nil {
		t.Fatal(err)
	}
	if _, err := testDB.GetVersionMap(ctx, v.ModulePath, v.Version); err != nil {
		t.Fatal(err)
	}

	if err := testDB.DeleteModule(ctx, v.ModulePath, v.Version); err != nil {
		t.Fatal(err)
	}
	if _, err := testDB.GetModuleInfo(ctx, v.ModulePath, v.Version); !errors.Is(err, derrors.NotFound) {
		t.Errorf("got %v, want NotFound", err)
	}

	var x int
	err := testDB.Underlying().QueryRow(ctx, "SELECT 1 FROM imports_unique WHERE from_module_path = $1",
		v.ModulePath).Scan(&x)
	if err != sql.ErrNoRows {
		t.Errorf("imports_unique: got %v, want ErrNoRows", err)
	}
	err = testDB.Underlying().QueryRow(
		ctx,
		"SELECT 1 FROM version_map WHERE module_path = $1 AND resolved_version = $2",
		v.ModulePath, v.Version).Scan(&x)
	if err != sql.ErrNoRows {
		t.Errorf("version_map: got %v, want ErrNoRows", err)
	}
}

func TestDeleteFromSearch(t *testing.T) {
	t.Parallel()
	ctx := context.Background()

	const (
		modulePath1 = "deleteme.com"
		modulePath2 = "example.com"
	)

	initial := []searchDocumentRow{
		{modulePath1 + "/p1", modulePath1, "v0.0.9", 0}, // oldest version of same module
		{modulePath1 + "/p2", modulePath1, "v1.1.0", 0}, // older version of same module
		{modulePath1 + "/p4", modulePath1, "v1.9.0", 0}, // newer version of same module
		{"other.org/p2", "other.org", "v1.1.0", 0},      // older version of a different module
	}

	insertInitial := func(db *DB) {
		t.Helper()
		for _, r := range initial {
			sm := sample.Module(r.ModulePath, r.Version, strings.TrimPrefix(r.PackagePath, r.ModulePath+"/"))
			db.MustInsertModule(t, sm)
		}
		// Older versions are deleted by InsertModule, so only the newest versions are here.
		checkSearchDocuments(ctx, t, db, initial[2:])
	}

	t.Run("deleteModuleFromSearchDocuments", func(t *testing.T) {
		// Non-empty list of packages tested above. This tests an empty list.
		testDB, release := acquire(t)
		defer release()
		insertInitial(testDB)

		if err := deleteModuleFromSearchDocuments(ctx, testDB.db, modulePath1); err != nil {
			t.Fatal(err)
		}
		checkSearchDocuments(ctx, t, testDB, []searchDocumentRow{
			{"other.org/p2", "other.org", "v1.1.0", 0}, // other module not deleted
		})
	})
	t.Run("deleteOtherModulePackagesFromSearchDocuments", func(t *testing.T) {
		testDB, release := acquire(t)
		defer release()

		// Insert a module with two packages.
		m0 := sample.Module(modulePath1, "v1.0.0", "p1", "p2")
		testDB.MustInsertModule(t, m0)
		// Insert another module that imports p2.
		mref := sample.Module(modulePath2, "v1.0.0")
		u := sample.UnitForPackage(modulePath2+"/ref", modulePath2, mref.Version, "ref", true)
		u.Imports = []string{modulePath1 + "/p2"}
		sample.AddUnit(mref, u)
		testDB.MustInsertModule(t, mref)

		// Later version of module does not have p1.
		m1 := sample.Module(modulePath1, "v1.1.0", "p2", "p3")
		testDB.MustInsertModule(t, m1)

		// p1 should be gone, p2 should be there with the same
		// imported_by_count, and p3 should be there with a zero count.
		want := []searchDocumentRow{
			{modulePath1 + "/p2", modulePath1, "v1.1.0", 1},
			{modulePath1 + "/p3", modulePath1, "v1.1.0", 0},
			{modulePath2 + "/ref", modulePath2, "v1.0.0", 0},
		}
		checkSearchDocuments(ctx, t, testDB, want)
	})
}

type searchDocumentRow struct {
	PackagePath, ModulePath, Version string
	ImportedByCount                  int
}

func readSearchDocuments(ctx context.Context, db *DB) ([]searchDocumentRow, error) {
	rows, err := database.CollectStructs[searchDocumentRow](ctx, db.db, `SELECT package_path, module_path, version, imported_by_count FROM search_documents`)
	if err != nil {
		return nil, err
	}
	return rows, nil
}

func checkSearchDocuments(ctx context.Context, t *testing.T, db *DB, want []searchDocumentRow) {
	t.Helper()
	got, err := readSearchDocuments(ctx, db)
	if err != nil {
		t.Fatal(err)
	}
	less := func(r1, r2 searchDocumentRow) bool {
		if r1.PackagePath != r2.PackagePath {
			return r1.PackagePath < r2.PackagePath
		}
		if r1.ModulePath != r2.ModulePath {
			return r1.ModulePath < r2.ModulePath
		}
		return r1.Version < r2.Version
	}
	sort.Slice(got, func(i, j int) bool { return less(got[i], got[j]) })
	sort.Slice(want, func(i, j int) bool { return less(want[i], want[j]) })
	if diff := cmp.Diff(want, got); diff != "" {
		t.Errorf("search documents mismatch (-want, +got):\n%s", diff)
	}
}

func TestDeletePseudoversionsExcept(t *testing.T) {
	t.Parallel()
	ctx := context.Background()
	testDB, release := acquire(t)
	defer release()

	pseudo1 := "v0.0.0-20190904010203-89fb59e2e920"
	versions := []string{
		sample.VersionString,
		pseudo1,
		"v0.0.0-20190904010203-89fb59e2e920",
		"v0.0.0-20190904010203-89fb59e2e920",
	}
	for _, v := range versions {
		testDB.MustInsertModule(t, sample.Module(sample.ModulePath, v, ""))
	}
	if err := testDB.DeletePseudoversionsExcept(ctx, sample.ModulePath, pseudo1); err != nil {
		t.Fatal(err)
	}
	mods, _, err := testDB.GetPathVersions(ctx, sample.ModulePath, "", 800, version.TypeRelease)
	if err != nil {
		t.Fatal(err)
	}
	if len(mods) != 1 && mods[0].Version != sample.VersionString {
		t.Errorf("module version %q was not found", sample.VersionString)
	}
	mods, _, err = testDB.GetPathVersions(ctx, sample.ModulePath, "", 10, version.TypePseudo)
	if err != nil {
		t.Fatal(err)
	}
	if len(mods) != 1 {
		t.Fatalf("pseudoversions expected to be deleted were not")
	}
	if mods[0].Version != pseudo1 {
		t.Errorf("got %q; want %q", mods[0].Version, pseudo1)
	}
}
