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

package generic

import (
	"context"

	"code.forgejo.org/f3/gof3/v3/path"
)

type MirrorOptions struct {
	noremap bool
}

func NewMirrorOptions() *MirrorOptions {
	return &MirrorOptions{}
}

func (o *MirrorOptions) SetNoRemap(noremap bool) *MirrorOptions {
	o.noremap = noremap
	return o
}

func NodeMirror(ctx context.Context, origin, destination NodeInterface, options *MirrorOptions) {
	origin.Trace("origin '%s' | destination '%s'", origin.GetCurrentPath().ReadableString(), destination.GetCurrentPath().ReadableString())
	origin.Trace("start unify references")
	for _, reference := range NodeCollectReferences(ctx, origin) {
		origin.Trace("unify reference %s", reference)
		TreeUnifyPath(ctx, origin.GetTree(), reference, destination.GetTree(), NewUnifyOptions(destination.GetTree()))
	}
	origin.Trace("end unify references")
	originParents := origin.GetParent().GetCurrentPath()
	destinationParents := destination.GetParent().GetCurrentPath()
	NodeUnify(ctx, origin, originParents, destination, destinationParents, NewUnifyOptions(destination.GetTree()))
}

func TreeMirror(ctx context.Context, originTree, destinationTree TreeInterface, path path.Path, options *MirrorOptions) {
	originTree.Trace("'%s'", path.ReadableString())
	TreeUnifyPath(ctx, originTree, path, destinationTree, NewUnifyOptions(destinationTree))
	TreeParallelApply(ctx, originTree, path, destinationTree, NewParallelApplyOptions(func(ctx context.Context, origin, destination NodeInterface) {
		NodeMirror(ctx, origin, destination, NewMirrorOptions())
	}))
}

func TreePartialMirror(ctx context.Context, originTree TreeInterface, originPath path.Path, destinationTree TreeInterface, destinationPath path.Path, options *MirrorOptions) {
	originTree.Trace("'%s => %s'", originPath, destinationPath)
	originNode := originTree.MustFind(originPath)
	destinationNode := destinationTree.MustFind(destinationPath)
	NodeMirror(ctx, originNode, destinationNode, NewMirrorOptions())
}
