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

package cli

import (
	"fmt"

	"github.com/spf13/cobra"
)

// newCredentialsCommand creates the credentials command.
func (c *CLI) newCredentialsCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "credentials",
		Short: "Manage S3 credentials (rotate)",
		Long: `Manage S3 credentials for data operations (advanced mode only).

Shows current S3 credential info and allows rotating the secret access key.
The access key ID and bucket name are permanent and cannot be changed.`,
		Annotations: map[string]string{
			"mode": "advanced",
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runCredentialsShow()
		},
	}

	cmd.AddCommand(c.newCredentialsShowCommand())
	cmd.AddCommand(c.newCredentialsRotateCommand())

	return cmd
}

// newCredentialsShowCommand creates the credentials show subcommand.
func (c *CLI) newCredentialsShowCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "show",
		Short: "Show current S3 credential info",
		Long: `Show current S3 credential info (no secrets exposed).

Displays the access key ID, bucket name, and data backend type.`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runCredentialsShow()
		},
	}
}

// newCredentialsRotateCommand creates the credentials rotate subcommand.
func (c *CLI) newCredentialsRotateCommand() *cobra.Command {
	var skipConfirmation bool

	cmd := &cobra.Command{
		Use:   "rotate",
		Short: "Rotate S3 secret access key",
		Long: `Rotate the S3 secret access key.

This will:
  • Invalidate the old secret key immediately
  • Update your local backup key file
  • Your backup key copies are now OUT OF DATE

After rotation, re-export your backup key file:
  privatebackup export-key --output /secure/location/privatebackup.pem`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runCredentialsRotate(skipConfirmation)
		},
	}

	cmd.Flags().BoolVarP(&skipConfirmation, "yes", "y", false, "Skip confirmation prompt")

	return cmd
}

// runCredentialsShow shows current S3 credential info.
func (c *CLI) runCredentialsShow() error {
	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)
	}

	// Check mode
	ctx, cancel := c.GetContext()
	defer cancel()

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

	if modeResp.Mode != "advanced" {
		c.renderer.Error("Credentials management requires advanced mode")
		c.renderer.Info("Switch with: privatebackup mode advanced")
		return fmt.Errorf("advanced mode required")
	}

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

	c.renderer.Output(creds, func() {
		c.renderer.Heading("S3 Credentials")
		c.renderer.Newline()

		if !creds.HasCredentials {
			c.renderer.KeyValue("Data Backend", "REST (legacy)")
			c.renderer.Newline()
			c.renderer.Info("This account uses legacy REST authentication.")
			c.renderer.Info("S3 credentials are not available.")
			return
		}

		c.renderer.KeyValue("Access Key ID", creds.AccessKeyID)
		c.renderer.KeyValue("Bucket Name", creds.BucketName)
		c.renderer.KeyValue("Data Backend", "S3 (AWS Sig V4)")
		c.renderer.Newline()
		c.renderer.Info("💡 Access Key ID and Bucket Name are permanent.")
		c.renderer.Info("   Secret Key can be rotated with: privatebackup credentials rotate")
	})

	return nil
}

// runCredentialsRotate rotates the S3 secret access key.
func (c *CLI) runCredentialsRotate(skipConfirmation bool) error {
	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)
	}

	// Check mode
	ctx, cancel := c.GetContext()
	defer cancel()

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

	if modeResp.Mode != "advanced" {
		c.renderer.Error("Credential rotation requires advanced mode")
		c.renderer.Info("Switch with: privatebackup mode advanced")
		return fmt.Errorf("advanced mode required")
	}

	// Check if S3 credentials exist
	creds, err := c.client.GetCredentials(ctx)
	if err != nil {
		return fmt.Errorf("failed to get credentials: %w", err)
	}

	if !creds.HasCredentials {
		c.renderer.Error("No S3 credentials to rotate")
		c.renderer.Info("This account uses legacy REST authentication.")
		return fmt.Errorf("no S3 credentials")
	}

	// Confirmation prompt
	if !skipConfirmation {
		c.renderer.Newline()
		c.renderer.Warning("Rotating your S3 secret key will:")
		c.renderer.Printf("  • Invalidate the old secret key immediately\n")
		c.renderer.Printf("  • Update your local backup key file\n")
		c.renderer.Printf("  • Your backup key copies will be OUT OF DATE\n")
		c.renderer.Newline()
		c.renderer.Warning("After rotation, re-export your backup key file:")
		c.renderer.Printf("  privatebackup export-key --output /secure/location/privatebackup.pem\n")
		c.renderer.Newline()

		confirmed, err := c.prompter.Confirm("Continue?", false)
		if err != nil {
			return fmt.Errorf("prompt error: %w", err)
		}
		if !confirmed {
			c.renderer.Info("Rotation cancelled.")
			return nil
		}
	}

	c.renderer.Info("Rotating S3 credentials...")

	resp, err := c.client.RotateCredentials(ctx)
	if err != nil {
		c.renderer.Error("Credential rotation failed")
		return fmt.Errorf("rotation failed: %w", err)
	}

	c.renderer.Output(resp, func() {
		c.renderer.Newline()
		c.renderer.Success("S3 secret key rotated")
		c.renderer.Success("Local backup key file updated")

		if resp.Warning != "" {
			c.renderer.Newline()
			c.renderer.Warning(resp.Warning)
		}

		c.renderer.Newline()
		c.renderer.Warning("Remember to re-export your backup key file to secure locations!")
		c.renderer.Info("  privatebackup export-key --output /secure/location/privatebackup.pem")
	})

	return nil
}
