package cmd

import (
	"fmt"

	"github.com/spf13/cobra"

	"chezmoi.io/chezmoi/v2/internal/chezmoi"
)

func (c *Config) newForgetCmd() *cobra.Command {
	forgetCmd := &cobra.Command{
		GroupID:           groupIDDaily,
		Use:               "forget target...",
		Aliases:           []string{"unmanage"},
		Short:             "Remove a target from the source state",
		Long:              mustLongHelp("forget"),
		Example:           example("forget"),
		ValidArgsFunction: c.targetValidArgs,
		Args:              cobra.MinimumNArgs(1),
		RunE:              c.makeRunEWithSourceState(c.runForgetCmd),
		Annotations: newAnnotations(
			modifiesSourceDirectory,
			persistentStateModeReadWrite,
		),
	}

	return forgetCmd
}

func (c *Config) runForgetCmd(cmd *cobra.Command, args []string, sourceState *chezmoi.SourceState) error {
	targetRelPaths, err := c.targetRelPaths(sourceState, args, targetRelPathsOptions{})
	if err != nil {
		return err
	}

	for _, targetRelPath := range targetRelPaths {
		sourceStateEntry := sourceState.MustEntry(targetRelPath)

		// Skip source state entries that are not regular entries. These are
		// removes or externals, which we cannot handle.
		switch sourceStateOrigin := sourceStateEntry.Origin(); sourceStateOrigin.(type) {
		case chezmoi.SourceStateOriginAbsPath:
			// OK, keep going.
		case chezmoi.SourceStateOriginRemove:
			c.errorf("warning: %s: cannot forget entry from remove\n", targetRelPath)
			continue
		case *chezmoi.External:
			c.errorf("warning: %s: cannot forget entry from external %s\n", targetRelPath, sourceStateOrigin.OriginString())
			continue
		default:
			panic(fmt.Sprintf("%s: %T: unknown source state origin type", targetRelPath, sourceStateOrigin))
		}

		relPath := sourceStateEntry.SourceRelPath().RelPath()
		if relPath.IsEmpty() {
			c.errorf("warning: %s: ignoring implicitly managed file\n", targetRelPath)
			continue
		}

		sourceAbsPath := c.SourceDirAbsPath.Join(relPath)
		if !c.force {
			choice, err := c.promptChoice(fmt.Sprintf("Remove %s", sourceAbsPath), choicesYesNoAllQuit)
			if err != nil {
				return err
			}
			switch choice {
			case "yes":
			case "no":
				continue
			case "all":
				c.force = false
			case "quit":
				return nil
			}
		}
		if err := c.sourceSystem.RemoveAll(sourceAbsPath); err != nil {
			return err
		}

		targetAbsPath := c.DestDirAbsPath.Join(targetRelPath)
		if err := c.persistentState.Delete(chezmoi.EntryStateBucket, targetAbsPath.Bytes()); err != nil {
			return err
		}
	}

	return nil
}
