// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT

package f3

import (
	"context"
	"testing"

	filesystem_options "code.forgejo.org/f3/gof3/v3/forges/filesystem/options"
	forgejo_options "code.forgejo.org/f3/gof3/v3/forges/forgejo/options"
	helpers_repository "code.forgejo.org/f3/gof3/v3/forges/helpers/repository"
	tests_repository "code.forgejo.org/f3/gof3/v3/forges/helpers/tests/repository"
	"code.forgejo.org/f3/gof3/v3/logger"
	f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3"
	"code.forgejo.org/f3/gof3/v3/tree/generic"
	tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestNodeRepositoryDriverMirrorNoop(t *testing.T) {
	ctx := context.Background()
	url := t.TempDir()
	repositoryHelper := tests_repository.NewTestHelper(t, url, nil)
	repositoryHelper.CreateRepositoryContent("").PushMirror()
	log := logger.NewCaptureLogger()
	log.SetLevel(logger.Trace)

	log.Reset()
	helpers_repository.GitMirror(ctx, log, url, url, "")
	assert.Contains(t, log.String(), "do nothing")

	log.Reset()
	helpers_repository.GitMirrorRef(ctx, log, url, "fakeref", url, "fakeref")
	assert.Contains(t, log.String(), "do nothing")
}

func TestNodeRepositoryDriverMirrorForgejo(t *testing.T) {
	ctx := context.Background()
	log := logger.NewCaptureLogger()
	log.SetLevel(logger.Trace)

	testForgejo := tests_forge.GetFactory(forgejo_options.Name)()
	opts := testForgejo.NewOptions(t)
	forgeTree := generic.GetFactory("f3")(ctx, opts)

	forgeTree.Trace("======= build fixture")
	fixtureTree := generic.GetFactory("f3")(ctx, tests_forge.GetFactory(filesystem_options.Name)().NewOptions(t))
	TreeBuildPartial(t, "F3", testForgejo.GetKindExceptions(), opts, fixtureTree)

	forgeTree.Trace("======= mirror fixture to forge")

	generic.TreeMirror(ctx, fixtureTree, forgeTree, generic.NewPathFromString(""), generic.NewMirrorOptions())

	forgeTree.Trace("======= NodeRepositoryDriverMirror from a forgejo project to a directory")

	repositoryPath := generic.TreePathRemap(ctx, fixtureTree, generic.NewPathFromString("/forge/users/10111/projects/74823/repositories/vcs"), forgeTree)
	require.False(t, repositoryPath.Empty())
	repository := forgeTree.Find(repositoryPath)
	repositoryURL := repository.GetDriver().(f3_tree.RepositoryNodeDriverProxyInterface).GetRepositoryURL()
	internalRef := repository.GetDriver().(f3_tree.RepositoryNodeDriverProxyInterface).GetRepositoryInternalRef()

	log.Reset()
	destination := t.TempDir()
	tests_repository.NewTestHelper(t, destination, nil)
	helpers_repository.GitMirror(ctx, log, repositoryURL, destination, internalRef)
	require.Contains(t, log.String(), "fetch fetchMirror")

	forgeTree.Trace("======= NodeRepositoryDriverMirror from one forgejo project to another forgejo project")

	otherRepositoryPath := generic.TreePathRemap(ctx, fixtureTree, generic.NewPathFromString("/forge/users/20222/projects/99099/repositories/vcs"), forgeTree)
	require.False(t, otherRepositoryPath.Empty())
	otherRepository := forgeTree.Find(otherRepositoryPath)
	otherRepositoryURL := otherRepository.GetDriver().(f3_tree.RepositoryNodeDriverProxyInterface).GetRepositoryURL()
	otherInternalRef := otherRepository.GetDriver().(f3_tree.RepositoryNodeDriverProxyInterface).GetRepositoryInternalRef()

	log.Reset()
	helpers_repository.GitMirror(ctx, log, repositoryURL, otherRepositoryURL, otherInternalRef)
	require.Contains(t, log.String(), "+refs/")

	forgeTree.Trace("======= NodeRepositoryDriverMirror from a directory to a forgejo project")

	log.Reset()
	repositoryHelper := tests_repository.NewTestHelper(t, destination, nil)
	content := "SOMETHING DIFFERENT"
	repositoryHelper.CreateRepositoryContent(content).PushMirror()
	helpers_repository.GitMirror(ctx, log, destination, otherRepositoryURL, otherInternalRef)
	require.Contains(t, log.String(), "+refs/")
	verificationDir := t.TempDir()
	repositoryHelper = tests_repository.NewTestHelper(t, verificationDir, nil)
	helpers_repository.GitMirror(ctx, log, otherRepositoryURL, verificationDir, "")
	repositoryHelper.AssertReadmeContains(content)

	forgeTree.Trace("======= NodeRepositoryDriverMirrorRef from a forgejo project to a directory")

	masterRef := "refs/heads/master"
	forgejoRef := "refs/forgejo/test"
	directoryRef := "refs/directory/test"

	log.Reset()
	helpers_repository.GitMirrorRef(ctx, log, repositoryURL, masterRef, destination, directoryRef)
	require.Contains(t, log.String(), "new branch")
	directorySha := helpers_repository.GitGetSha(ctx, log, destination, directoryRef)

	forgeTree.Trace("======= NodeRepositoryDriverMirrorRef from one forgejo project to another forgejo project")

	log.Reset()
	otherForgejoRef := "refs/otherforgejo/test"
	otherDirectoryRef := "refs/otherdirectory/test"
	helpers_repository.GitMirrorRef(ctx, log, repositoryURL, masterRef, otherRepositoryURL, otherForgejoRef)
	helpers_repository.GitMirrorRef(ctx, log, otherRepositoryURL, otherForgejoRef, destination, otherDirectoryRef)
	assert.EqualValues(t, directorySha, helpers_repository.GitGetSha(ctx, log, destination, otherDirectoryRef))

	forgeTree.Trace("======= NodeRepositoryDriverMirrorRef from a directory to a forgejo project")

	log.Reset()
	helpers_repository.GitMirrorRef(ctx, log, verificationDir, masterRef, otherRepositoryURL, forgejoRef)
	masterSha := helpers_repository.GitGetSha(ctx, log, verificationDir, masterRef)
	helpers_repository.GitMirrorRef(ctx, log, otherRepositoryURL, forgejoRef, verificationDir, directoryRef)
	assert.EqualValues(t, masterSha, helpers_repository.GitGetSha(ctx, log, verificationDir, directoryRef))
}
