package screens

import (
	"charm.land/bubbles/v2/key"
	tea "charm.land/bubbletea/v2"

	"git.secluded.site/keld/internal/ui"
)

// PreviewFunc returns the formatted command preview text. It is
// called asynchronously from Init via a tea.Cmd. The returned string
// should match the format of [restic.DryRun].
type PreviewFunc func() string

// previewMsg carries the result of the async preview generation.
type previewMsg struct {
	text string
}

// Confirm is a Screen adapter that shows the resolved restic command
// and waits for the user to confirm execution. Enter proceeds,
// Esc goes back.
//
// When showCommand is true, Init returns DoneCmd immediately without
// calling the preview function — the session completes and the caller
// prints the dry-run output through the normal --show-command path.
type Confirm struct {
	previewFn   PreviewFunc
	showCommand bool
	partial     bool
	preview     string
	selection   string
}

// NewConfirm creates a confirmation screen. The previewFn is called
// to generate the command preview text. When showCommand is true,
// the screen auto-completes without user interaction.
func NewConfirm(previewFn PreviewFunc, showCommand bool) *Confirm {
	return &Confirm{
		previewFn:   previewFn,
		showCommand: showCommand,
	}
}

// Init starts the preview generation. In --show-command mode, it
// skips the preview and returns DoneCmd immediately.
func (c *Confirm) Init() tea.Cmd {
	c.selection = ""

	if c.showCommand {
		return ui.DoneCmd
	}

	return func() tea.Msg {
		return previewMsg{text: c.previewFn()}
	}
}

// Update handles messages. Esc navigates back, Enter confirms.
func (c *Confirm) Update(msg tea.Msg) (ui.Screen, tea.Cmd) {
	switch msg := msg.(type) {
	case previewMsg:
		c.preview = msg.text
		return c, nil

	case tea.KeyPressMsg:
		if msg.Code == tea.KeyEscape {
			return c, ui.BackCmd
		}
		if msg.Code == tea.KeyEnter && c.preview != "" {
			c.selection = "confirmed"
			return c, ui.DoneCmd
		}
	}

	return c, nil
}

// View renders the command preview. When partial is set, a note
// is appended explaining the preview may be incomplete.
func (c *Confirm) View() string {
	if c.preview == "" {
		return ""
	}
	if !c.partial {
		return c.preview
	}
	return c.preview + "\n" + partialNote
}

// partialNote is shown below the preview when the command has no
// dedicated TUI screens, meaning the session could not collect all
// inputs interactively.
const partialNote = "Note: this preview may be incomplete. " +
	"Additional prompts may follow after confirmation.\n" +
	"Use --show-command to see the final command after all inputs are collected."

// Title returns the screen's display title.
func (c *Confirm) Title() string { return "Confirm execution" }

// KeyBindings returns bindings for the help bar.
func (c *Confirm) KeyBindings() []key.Binding {
	return []key.Binding{
		key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "execute")),
	}
}

// SetPartial marks the preview as potentially incomplete because
// the command has no dedicated TUI screens to collect all inputs.
func (c *Confirm) SetPartial(partial bool) { c.partial = partial }

// Selection returns "confirmed" after the user presses Enter, or ""
// if the screen has not been confirmed yet.
func (c *Confirm) Selection() string { return c.selection }
