// SPDX-License-Identifier: GPL-3.0-or-later

// Package cli provides the forget command.
package cli

import (
	"fmt"

	"github.com/spf13/cobra"
)

// ForgetOptions contains options for the forget command.
type ForgetOptions struct {
	KeepLast    int
	KeepDaily   int
	KeepWeekly  int
	KeepMonthly int
	KeepYearly  int
	KeepTag     []string
	Prune       bool
	DryRun      bool
	Compact     bool
}

// newForgetCommand creates the forget command.
func (c *CLI) newForgetCommand() *cobra.Command {
	opts := &ForgetOptions{}

	cmd := &cobra.Command{
		Use:   "forget",
		Short: "Remove old snapshots",
		Long: `Apply a retention policy to remove old snapshots.

This frees up storage space by removing snapshots you no longer need.
Use --dry-run first to see what would be removed.`,
		Example: `  # Preview what would be removed
  privatebackup forget --keep-daily 7 --keep-weekly 4 --dry-run

  # Remove old snapshots (keep last week + last 4 weeks)
  privatebackup forget --keep-daily 7 --keep-weekly 4 --prune

  # Keep tagged snapshots forever
  privatebackup forget --keep-last 5 --keep-tag important --prune`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runForget(opts)
		},
	}

	flags := cmd.Flags()
	flags.IntVar(&opts.KeepLast, "keep-last", 0, "Keep last n snapshots")
	flags.IntVar(&opts.KeepDaily, "keep-daily", 0, "Keep n daily snapshots")
	flags.IntVar(&opts.KeepWeekly, "keep-weekly", 0, "Keep n weekly snapshots")
	flags.IntVar(&opts.KeepMonthly, "keep-monthly", 0, "Keep n monthly snapshots")
	flags.IntVar(&opts.KeepYearly, "keep-yearly", 0, "Keep n yearly snapshots")
	flags.StringSliceVar(&opts.KeepTag, "keep-tag", nil, "Never remove snapshots with this tag")
	flags.BoolVar(&opts.Prune, "prune", false, "Actually remove data (not just snapshot metadata)")
	flags.BoolVarP(&opts.DryRun, "dry-run", "n", false, "Show what would be removed without doing it")
	flags.BoolVar(&opts.Compact, "compact", false, "Reclaim space after forgetting (slower)")

	return cmd
}

// runForget executes the forget command.
func (c *CLI) runForget(opts *ForgetOptions) error {
	// Validate that at least one keep flag is specified
	if opts.KeepLast == 0 && opts.KeepDaily == 0 && opts.KeepWeekly == 0 &&
		opts.KeepMonthly == 0 && opts.KeepYearly == 0 {
		return fmt.Errorf("at least one --keep-* flag must be specified")
	}

	// Check backend connection
	if err := c.checkBackendConnection(); err != nil {
		if IsBackendNotRunning(err) {
			c.renderer.Error("Cannot connect to backend daemon")
			c.renderer.Info("Start it with: privatebackup daemon start")
			return err
		}
		return fmt.Errorf("backend error: %w", err)
	}

	c.renderer.Section("Applying retention policy")
	c.renderer.Newline()

	// Display policy
	if opts.KeepLast > 0 {
		c.renderer.KeyValue("Keep last", fmt.Sprintf("%d", opts.KeepLast))
	}
	if opts.KeepDaily > 0 {
		c.renderer.KeyValue("Keep daily", fmt.Sprintf("%d", opts.KeepDaily))
	}
	if opts.KeepWeekly > 0 {
		c.renderer.KeyValue("Keep weekly", fmt.Sprintf("%d", opts.KeepWeekly))
	}
	if opts.KeepMonthly > 0 {
		c.renderer.KeyValue("Keep monthly", fmt.Sprintf("%d", opts.KeepMonthly))
	}
	if opts.KeepYearly > 0 {
		c.renderer.KeyValue("Keep yearly", fmt.Sprintf("%d", opts.KeepYearly))
	}
	if len(opts.KeepTag) > 0 {
		c.renderer.KeyValue("Keep tags", fmt.Sprintf("%v", opts.KeepTag))
	}
	c.renderer.Newline()

	if opts.DryRun {
		c.renderer.Info("Dry run - no snapshots will be removed")
		c.renderer.Newline()

		c.renderer.Section("Snapshots that would be removed")
		c.renderer.Info("(Backend would provide actual list)")
		c.renderer.Newline()

		c.renderer.Section("Summary")
		c.renderer.KeyValue("Snapshots to remove", "0 (simulated)")
		c.renderer.KeyValue("Data to remove", "0 B")

		return nil
	}


	// Get list of snapshots that would be removed (mock)
	ctx, cancel := c.GetContext()
	defer cancel()

	snapshots, err := c.client.ListSnapshots(ctx)
	if err != nil {
		return fmt.Errorf("failed to list snapshots: %w", err)
	}

	if len(snapshots) == 0 {
		c.renderer.Info("No snapshots to remove")
		return nil
	}

	// In reality, we'd apply the retention policy and show what would be removed
	c.renderer.Info("This command would apply the retention policy and remove old snapshots.")
	c.renderer.Newline()

	if !opts.Prune {
		c.renderer.Warning("Use --prune to actually remove data (not just snapshot metadata)")
		return nil
	}

	// Confirm
	confirmed, err := c.prompter.Confirm("Continue with removing snapshots?", false)
	if err != nil {
		return err
	}
	if !confirmed {
		c.renderer.Info("Operation cancelled")
		return nil
	}

	// Execute (would call backend)
	c.renderer.Info("Removing snapshots...")
	c.renderer.Success("Retention policy applied")

	if opts.Compact {
		c.renderer.Info("Compacting repository...")
		c.renderer.Success("Repository compacted")
	}

	return nil
}
