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

// Package cli provides the paths command for backup path management.
package cli

import (
	"fmt"
	"path/filepath"

	"github.com/privatebackup/client-frontend-unix/internal/client"
	"github.com/privatebackup/client-frontend-unix/internal/output"
	"github.com/spf13/cobra"
)

// newPathsCommand creates the paths command.
func (c *CLI) newPathsCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "paths",
		Short: "Manage backup paths",
		Long: `View and manage directories to be backed up.

Add or remove directories from your backup configuration.
Each path must be an existing directory.`,
		Example: `  # List current backup paths
  privatebackup paths

  # Add a path
  privatebackup paths add ~/Documents

  # Remove a path
  privatebackup paths remove ~/Downloads`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runPathsList()
		},
	}

	// Add subcommands
	cmd.AddCommand(c.newPathsAddCommand())
	cmd.AddCommand(c.newPathsRemoveCommand())

	return cmd
}

// runPathsList shows the configured backup paths.
func (c *CLI) runPathsList() error {
	// 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)
	}

	ctx, cancel := c.GetContext()
	defer cancel()

	resp, err := c.client.ListPaths(ctx)
	if err != nil {
		return fmt.Errorf("failed to get paths: %w", err)
	}

	c.renderer.Output(resp, func() {
		c.renderer.Heading("Backup Paths")
		c.renderer.Newline()

		if resp.TotalPaths == 0 {
			c.renderer.Info("No backup paths configured")
			c.renderer.Newline()
			c.renderer.Info("Add paths with: privatebackup paths add <directory>")
			return
		}

		for _, path := range resp.Paths {
			status := "✓"
			if !path.Exists {
				status = "✗ (not found)"
			} else if !path.IsDir {
				status = "✗ (not a directory)"
			} else if path.AccessError != "" {
				status = fmt.Sprintf("✗ (%s)", path.AccessError)
			}

			c.renderer.Printf("  %s %s\n", status, path.Path)

			if path.Exists && path.IsDir && path.SizeBytes > 0 {
				c.renderer.Printf("      Size: %s, Files: %d\n",
					output.FormatSize(path.SizeBytes), path.FileCount)
			}
		}
		c.renderer.Newline()
		c.renderer.KeyValue("Total paths", fmt.Sprintf("%d", resp.TotalPaths))
	})

	return nil
}

// newPathsAddCommand creates the paths add subcommand.
func (c *CLI) newPathsAddCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "add <path>",
		Short: "Add a backup path",
		Long: `Add a directory to be backed up.

The path must exist and be a directory.`,
		Example: `  # Add Documents folder
  privatebackup paths add ~/Documents

  # Add with absolute path
  privatebackup paths add /home/user/projects`,
		Args: cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runPathsAdd(args[0])
		},
	}

	return cmd
}

// runPathsAdd adds a path to the backup configuration.
func (c *CLI) runPathsAdd(path string) error {
	// Expand and make absolute
	absPath, err := filepath.Abs(expandPath(path))
	if err != nil {
		return fmt.Errorf("invalid path: %w", err)
	}

	// 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)
	}

	ctx, cancel := c.GetContext()
	defer cancel()

	req := &client.PathAddRequest{
		Path: absPath,
	}

	resp, err := c.client.AddPath(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to add path: %w", err)
	}

	c.renderer.Success(fmt.Sprintf("Added: %s", absPath))
	c.renderer.KeyValue("Total paths", fmt.Sprintf("%d", resp.TotalPaths))

	return nil
}

// newPathsRemoveCommand creates the paths remove subcommand.
func (c *CLI) newPathsRemoveCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "remove <path>",
		Short: "Remove a backup path",
		Long: `Remove a directory from the backup configuration.

This does not delete any existing backups of the directory.`,
		Example: `  # Remove Downloads folder
  privatebackup paths remove ~/Downloads`,
		Args: cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runPathsRemove(args[0])
		},
	}

	return cmd
}

// runPathsRemove removes a path from the backup configuration.
func (c *CLI) runPathsRemove(path string) error {
	// Expand and make absolute
	absPath, err := filepath.Abs(expandPath(path))
	if err != nil {
		return fmt.Errorf("invalid path: %w", err)
	}

	// 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)
	}

	ctx, cancel := c.GetContext()
	defer cancel()

	req := &client.PathRemoveRequest{
		Path: absPath,
	}

	resp, err := c.client.RemovePath(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to remove path: %w", err)
	}

	c.renderer.Success(fmt.Sprintf("Removed: %s", absPath))
	c.renderer.KeyValue("Total paths", fmt.Sprintf("%d", resp.TotalPaths))

	return nil
}
