// Copyright 2025.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ui

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/Adembc/lazyssh/internal/core/domain"
	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"
)

// sshDefaults is now replaced by SSHFieldDefaults in defaults.go
// This variable references the centralized defaults for consistency
var sshDefaults = SSHFieldDefaults

type ServerFormMode int

const (
	ServerFormAdd ServerFormMode = iota
	ServerFormEdit
)

const (
	tabSeparator = "[gray]|[-] " // Tab separator with gray color

	// SessionType values (sessionTypeNone and sessionTypeSubsystem are in utils.go)
	sessionTypeDefault = "default"
)

type ServerForm struct {
	*tview.Flex               // The root container (includes header, form panel and hint bar)
	header        *AppHeader  // The app header
	formPanel     *tview.Flex // The actual form panel
	pages         *tview.Pages
	tabBar        *tview.TextView
	forms         map[string]*tview.Form
	currentTab    string
	tabs          []string
	tabAbbrev     map[string]string // Abbreviated tab names for narrow views
	mode          ServerFormMode
	original      *domain.Server
	onSave        func(domain.Server, *domain.Server)
	onCancel      func()
	app           *tview.Application // Reference to app for showing modals
	version       string             // Version for header
	commit        string             // Commit for header
	validation    *ValidationState   // Validation state for all fields
	helpPanel     *tview.TextView    // Help panel for field descriptions
	helpMode      HelpDisplayMode    // Current help display mode
	currentField  string             // Currently focused field
	mainContainer *tview.Flex        // Container for form and help panel
}

func NewServerForm(mode ServerFormMode, original *domain.Server) *ServerForm {
	// Create help panel
	helpPanel := tview.NewTextView().
		SetDynamicColors(true).
		SetWordWrap(true).
		SetScrollable(true)
	helpPanel.SetBorder(true).
		SetBorderPadding(0, 0, 1, 1).
		SetTitle(" Help ").
		SetTitleAlign(tview.AlignCenter)

	// Create main container for form and help
	mainContainer := tview.NewFlex().SetDirection(tview.FlexColumn)

	form := &ServerForm{
		Flex:          tview.NewFlex().SetDirection(tview.FlexRow),
		formPanel:     tview.NewFlex().SetDirection(tview.FlexRow),
		pages:         tview.NewPages(),
		tabBar:        tview.NewTextView().SetDynamicColors(true).SetTextAlign(tview.AlignCenter).SetRegions(true),
		forms:         make(map[string]*tview.Form),
		mode:          mode,
		original:      original,
		validation:    NewValidationState(),
		helpPanel:     helpPanel,
		helpMode:      HelpModeNormal, // Show help panel by default
		mainContainer: mainContainer,
		tabs: []string{
			"Basic",
			"Connection",
			"Forwarding",
			"Authentication",
			"Advanced",
		},
		tabAbbrev: map[string]string{
			"Basic":          "Basic",
			"Connection":     "Conn",
			"Forwarding":     "Fwd",
			"Authentication": "Auth",
			"Advanced":       "Adv",
		},
	}
	form.currentTab = "Basic"
	// Don't build here, wait for version info to be set
	return form
}

func (sf *ServerForm) build() {
	// Create header
	sf.header = NewAppHeader(sf.version, sf.commit, RepoURL)

	// Create forms for each tab
	sf.createBasicForm()
	sf.createConnectionForm()
	sf.createForwardingForm()
	sf.createAuthenticationForm()
	sf.createAdvancedForm()

	// Setup tab bar
	sf.updateTabBar()

	// Setup form panel
	sf.formPanel.SetBorder(true).
		SetTitle(" " + sf.titleForMode() + " ").
		SetTitleAlign(tview.AlignCenter).
		SetBorderColor(tcell.Color238).
		SetTitleColor(tcell.Color250)

	sf.formPanel.AddItem(sf.tabBar, 1, 0, false).
		AddItem(sf.pages, 0, 1, true)

	// Setup main container with form and help panel
	sf.mainContainer.Clear()

	// Responsive layout: hide help panel if window is too narrow
	sf.mainContainer.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {
		// Minimum width for showing help panel
		minWidthForHelp := 120

		// Clear and rebuild based on width
		sf.mainContainer.Clear()

		if width < minWidthForHelp || sf.helpMode == HelpModeOff {
			// Window too narrow or help is off - only show form
			sf.mainContainer.AddItem(sf.formPanel, 0, 1, true)
		} else {
			// Window wide enough - show both form and help
			sf.mainContainer.AddItem(sf.formPanel, 0, 3, true)
			sf.mainContainer.AddItem(sf.helpPanel, 0, 2, false)
			// Refresh help content to recalculate separator width on resize
			sf.updateHelp(sf.currentField)
		}

		return x, y, width, height
	})

	// Initial setup
	sf.mainContainer.AddItem(sf.formPanel, 0, 3, true)
	if sf.helpMode != HelpModeOff {
		sf.mainContainer.AddItem(sf.helpPanel, 0, 2, false)
	}

	// Create hint bar with same background as main screen's status bar
	hintBar := tview.NewTextView().SetDynamicColors(true)
	hintBar.SetBackgroundColor(tcell.Color235)
	hintBar.SetTextAlign(tview.AlignCenter)
	hintBar.SetText("[white]^H/^L[-] Navigate  • [white]^S[-] Save  • [white]Esc[-] Cancel")

	// Setup main container - header at top, hint bar at bottom
	sf.Flex.AddItem(sf.header, 2, 0, false).
		AddItem(sf.mainContainer, 0, 1, true).
		AddItem(hintBar, 1, 0, false)

	// Initialize help with first field
	sf.updateHelp("Alias")

	// Setup keyboard shortcuts
	sf.setupKeyboardShortcuts()

	// Set a draw function for the tab bar to update on each draw
	// This ensures the tab bar updates when the window is resized
	sf.tabBar.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
		// Update tab bar if size changed
		sf.updateTabBar()
		// Return the original dimensions
		return x, y, width, height
	})
}

func (sf *ServerForm) titleForMode() string {
	if sf.mode == ServerFormEdit {
		return "Edit Server"
	}
	return "Add Server"
}

func (sf *ServerForm) getCurrentTabIndex() int {
	for i, tab := range sf.tabs {
		if tab == sf.currentTab {
			return i
		}
	}
	return 0
}

func (sf *ServerForm) calculateTabsWidth(useAbbrev bool) int {
	width := 0
	for i, tab := range sf.tabs {
		tabName := tab
		if useAbbrev {
			tabName = sf.tabAbbrev[tab]
		}
		width += len(tabName) + 2 // space + name + space
		if i < len(sf.tabs)-1 {
			width += 3 // " | " separator
		}
	}
	return width
}

func (sf *ServerForm) determineDisplayMode(width int) string {
	if width <= 20 { // Width unknown or too small
		return "full"
	}

	fullWidth := sf.calculateTabsWidth(false)
	if fullWidth <= width-10 {
		return "full"
	}

	abbrevWidth := sf.calculateTabsWidth(true)
	if abbrevWidth <= width-10 {
		return "abbrev"
	}

	return "scroll"
}

func (sf *ServerForm) renderTab(tab string, isCurrent bool, useAbbrev bool, index int) string {
	tabName := tab
	if useAbbrev {
		tabName = sf.tabAbbrev[tab]
	}
	regionID := fmt.Sprintf("tab_%d", index)
	if isCurrent {
		return fmt.Sprintf("[%q][black:white:b] %s [-:-:-][%q] ", regionID, tabName, "")
	}
	return fmt.Sprintf("[%q][gray::u] %s [-:-:-][%q] ", regionID, tabName, "")
}

func (sf *ServerForm) renderScrollableTabs(currentIdx, width int) string {
	var tabText string
	availableWidth := width - 8 // Reserve space for scroll indicators

	// Calculate visible count
	visibleCount := sf.calculateVisibleTabCount(availableWidth)
	if visibleCount < 2 {
		visibleCount = 2
	}

	// Add left scroll indicator
	if currentIdx > 0 {
		tabText = "[gray]◀ [-]"
	}

	// Calculate range
	start, end := sf.calculateVisibleRange(currentIdx, visibleCount, len(sf.tabs))

	// Render visible tabs
	for i := start; i < end && i < len(sf.tabs); i++ {
		tabText += sf.renderTab(sf.tabs[i], sf.tabs[i] == sf.currentTab, true, i)
		if i < end-1 && i < len(sf.tabs)-1 {
			tabText += tabSeparator
		}
	}

	// Add right scroll indicator
	if currentIdx < len(sf.tabs)-1 {
		tabText += " [gray]▶[-]"
	}

	return tabText
}

func (sf *ServerForm) calculateVisibleTabCount(availableWidth int) int {
	visibleCount := 0
	currentWidth := 0

	for i := 0; i < len(sf.tabs) && currentWidth < availableWidth; i++ {
		abbrev := sf.tabAbbrev[sf.tabs[i]]
		tabWidth := len(abbrev) + 2
		if i > 0 {
			tabWidth += 3 // separator
		}
		if currentWidth+tabWidth <= availableWidth {
			visibleCount++
			currentWidth += tabWidth
		} else {
			break
		}
	}

	return visibleCount
}

func (sf *ServerForm) calculateVisibleRange(currentIdx, visibleCount, totalTabs int) (int, int) {
	halfVisible := visibleCount / 2
	start := currentIdx - halfVisible + 1
	end := start + visibleCount

	// Adjust boundaries
	if start < 0 {
		start = 0
		end = visibleCount
	}
	if end > totalTabs {
		end = totalTabs
		start = end - visibleCount
		if start < 0 {
			start = 0
		}
	}

	return start, end
}

func (sf *ServerForm) updateTabBar() {
	currentIdx := sf.getCurrentTabIndex()

	// Build tab text with scroll indicator if needed
	var tabText string

	// Check if we need to show scroll indicators
	x, y, width, height := sf.tabBar.GetInnerRect()
	_ = x
	_ = y
	_ = height

	displayMode := sf.determineDisplayMode(width)

	switch displayMode {
	case "scroll":
		tabText = sf.renderScrollableTabs(currentIdx, width)
	case "abbrev":
		// Show all tabs with abbreviated names
		for i, tab := range sf.tabs {
			tabText += sf.renderTab(tab, tab == sf.currentTab, true, i)
			if i < len(sf.tabs)-1 {
				tabText += tabSeparator
			}
		}
	default: // "full"
		// Show all tabs with full names
		for i, tab := range sf.tabs {
			tabText += sf.renderTab(tab, tab == sf.currentTab, false, i)
			if i < len(sf.tabs)-1 {
				tabText += tabSeparator
			}
		}
	}

	sf.tabBar.SetText(tabText)

	// Set up mouse click handler using highlight regions
	sf.tabBar.SetHighlightedFunc(func(added, removed, remaining []string) {
		if len(added) > 0 {
			// Extract tab index from region ID (format: "tab_0", "tab_1", etc)
			for _, regionID := range added {
				if len(regionID) > 4 && regionID[:4] == "tab_" {
					idx := int(regionID[4] - '0')
					if idx < len(sf.tabs) {
						sf.switchToTab(sf.tabs[idx])
					}
				}
			}
		}
	})
}

func (sf *ServerForm) switchToTab(tabName string) {
	for _, tab := range sf.tabs {
		if tab != tabName {
			continue
		}

		sf.currentTab = tabName
		sf.pages.SwitchToPage(tabName)
		sf.updateTabBar()

		// Set focus to the form in the newly selected tab
		if form, exists := sf.forms[tabName]; exists && sf.app != nil {
			sf.app.SetFocus(form)
		}
		break
	}
}

func (sf *ServerForm) nextTab() {
	for i, tab := range sf.tabs {
		if tab == sf.currentTab {
			// Loop to first tab if at the last tab
			if i == len(sf.tabs)-1 {
				sf.switchToTab(sf.tabs[0])
			} else {
				sf.switchToTab(sf.tabs[i+1])
			}
			break
		}
	}
}

func (sf *ServerForm) prevTab() {
	for i, tab := range sf.tabs {
		if tab == sf.currentTab {
			// Loop to last tab if at the first tab
			if i == 0 {
				sf.switchToTab(sf.tabs[len(sf.tabs)-1])
			} else {
				sf.switchToTab(sf.tabs[i-1])
			}
			break
		}
	}
}

// updateHelp updates the help panel with information for the given field
func (sf *ServerForm) updateHelp(fieldName string) {
	if sf.helpPanel == nil || sf.helpMode == HelpModeOff {
		return
	}

	sf.currentField = fieldName
	help := GetFieldHelp(fieldName)
	if help == nil {
		sf.helpPanel.SetText("[dim]No help available for this field[-]")
		return
	}

	var content string
	if sf.helpMode == HelpModeCompact {
		// Compact mode: single line
		example := ""
		if len(help.Examples) > 0 {
			example = help.Examples[0]
		}
		content = fmt.Sprintf("[yellow]%s:[-] %s", help.Field, escapeForTview(help.Description))
		if example != "" {
			content += fmt.Sprintf(" [dim](e.g., %s)[-]", escapeForTview(example))
		}
	} else {
		// Normal/Full mode: detailed help
		content = sf.formatDetailedHelp(help)
	}

	sf.helpPanel.SetText(content)
}

// escapeForTview escapes special characters for tview display
func escapeForTview(text string) string {
	// Use tview's own Escape function to properly escape text
	return tview.Escape(text)
}

// formatDetailedHelp formats detailed help content for a field
func (sf *ServerForm) formatDetailedHelp(help *FieldHelp) string {
	var b strings.Builder

	// Calculate separator width dynamically
	// Get the actual width of the help panel if possible
	separatorWidth := 40 // Default width
	if sf.helpPanel != nil {
		_, _, width, _ := sf.helpPanel.GetInnerRect()
		if width > 0 {
			separatorWidth = width // Fill entire width
		}
	}

	// Title with field name and separator below
	b.WriteString(fmt.Sprintf("[yellow::b]📖 %s[-::-]\n", help.Field))
	b.WriteString("[#444444]" + strings.Repeat("─", separatorWidth) + "[-]\n\n")

	// Description - needs escaping as it might contain brackets
	b.WriteString(fmt.Sprintf("%s\n\n", escapeForTview(help.Description)))

	// Syntax - needs escaping as it often contains brackets like [user@]
	if help.Syntax != "" {
		b.WriteString("[cyan]Syntax:[-] ")
		b.WriteString(fmt.Sprintf("%s\n\n", escapeForTview(help.Syntax)))
	}

	// Examples - needs escaping as they might contain special characters
	if len(help.Examples) > 0 {
		b.WriteString("[cyan]Examples:[-]\n")
		for _, ex := range help.Examples {
			b.WriteString(fmt.Sprintf("  • %s\n", escapeForTview(ex)))
		}
		b.WriteString("\n")
	}

	// Default value - already processed by formatDefaultValue, no additional escaping needed
	if help.Default != "" {
		b.WriteString(fmt.Sprintf("[dim]Default: %s[-]\n", help.Default))
	}

	// Version info - unlikely to contain brackets, but escape for safety
	if help.Since != "" {
		b.WriteString(fmt.Sprintf("[dim]Available since: %s[-]\n", escapeForTview(help.Since)))
	}

	return b.String()
}

// Note: toggleHelp and rebuildLayout were removed due to hang issues
// The help panel is now always visible on the right side

func (sf *ServerForm) setupKeyboardShortcuts() {
	// Set input capture for the main flex container
	sf.Flex.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		// Help panel is always visible - no toggle needed

		// Check for Ctrl key combinations with regular keys
		if event.Key() == tcell.KeyRune && event.Modifiers()&tcell.ModCtrl != 0 {
			switch event.Rune() {
			case 'h', 'H', 8: // 8 is ASCII for Ctrl+H (backspace)
				// Ctrl+H: Previous tab
				sf.prevTab()
				return nil
			case 'l', 'L', 12: // 12 is ASCII for Ctrl+L (form feed)
				// Ctrl+L: Next tab
				sf.nextTab()
				return nil
			case 's', 'S', 19: // 19 is ASCII for Ctrl+S
				// Ctrl+S: Save
				sf.handleSave()
				return nil
			}
		}

		// Handle special keys
		//nolint:exhaustive // We only handle specific keys and pass through others
		switch event.Key() {
		case tcell.KeyCtrlS:
			// Ctrl+S: Save (backup handler)
			sf.handleSave()
			return nil
		case tcell.KeyEscape:
			// ESC: Cancel
			sf.handleCancel()
			return nil
		case tcell.KeyCtrlH:
			// Ctrl+H: Previous tab (backup handler)
			sf.prevTab()
			return nil
		case tcell.KeyCtrlL:
			// Ctrl+L: Next tab (backup handler)
			sf.nextTab()
			return nil
		default:
			// Pass through all other keys
		}

		return event
	})
}

// setupFormShortcuts sets up keyboard shortcuts for a form
func (sf *ServerForm) setupFormShortcuts(form *tview.Form) {
	form.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		// Check for Ctrl key combinations
		if event.Key() == tcell.KeyRune && event.Modifiers()&tcell.ModCtrl != 0 {
			switch event.Rune() {
			case 'h', 'H', 8: // Ctrl+H: Previous tab
				sf.prevTab()
				return nil
			case 'l', 'L', 12: // Ctrl+L: Next tab
				sf.nextTab()
				return nil
			case 's', 'S', 19: // Ctrl+S: Save
				sf.handleSave()
				return nil
			}
		}

		// Handle special keys
		//nolint:exhaustive // We only handle specific keys and pass through others
		switch event.Key() {
		case tcell.KeyEscape:
			sf.handleCancel()
			return nil
		case tcell.KeyCtrlH:
			sf.prevTab()
			return nil
		case tcell.KeyCtrlL:
			sf.nextTab()
			return nil
		case tcell.KeyCtrlS:
			sf.handleSave()
			return nil
		default:
			// Pass through all other keys
		}

		return event
	})
}

// createOptionsWithDefault creates dropdown options with default value indicated
func createOptionsWithDefault(fieldName string, baseOptions []string) []string {
	defaultValue, hasDefault := sshDefaults[fieldName]
	if !hasDefault {
		return baseOptions
	}

	options := make([]string, len(baseOptions))
	for i, opt := range baseOptions {
		if opt == "" {
			options[i] = fmt.Sprintf("default [gray](%s)[-]", defaultValue)
		} else {
			options[i] = opt
		}
	}
	return options
}

// parseOptionValue extracts the actual value from an option (handles "default [gray](value)[-]" format)
func parseOptionValue(option string) string {
	// Check for colored default format
	if strings.HasPrefix(option, "default [gray](") && strings.HasSuffix(option, ")[-]") {
		return "" // Return empty string for default values
	}
	// Check for plain default format (backward compatibility)
	if strings.HasPrefix(option, "default (") && strings.HasSuffix(option, ")") {
		return "" // Return empty string for default values
	}
	return option
}

// findOptionIndex finds the index of a value in options slice
func (sf *ServerForm) findOptionIndex(options []string, value string) int {
	// Empty value should match "default [gray](...)[-]" or "default (...)" option
	if value == "" {
		for i, opt := range options {
			if strings.HasPrefix(opt, "default [gray](") || strings.HasPrefix(opt, "default (") {
				return i
			}
		}
	}

	// Look for exact match first
	for i, opt := range options {
		if strings.EqualFold(opt, value) {
			return i
		}
	}

	// Then look for options with descriptions (e.g., "none (-N)" matches "none")
	for i, opt := range options {
		// Extract the base value from options like "none (-N)"
		if spaceIdx := strings.Index(opt, " "); spaceIdx > 0 {
			baseOpt := opt[:spaceIdx]
			if strings.EqualFold(baseOpt, value) {
				return i
			}
		}
	}

	return 0 // Default to first option
}

// matchesSequence checks if all characters in pattern appear in sequence within text
func matchesSequence(text, pattern string) bool {
	if pattern == "" {
		return true
	}

	textIdx := 0
	for _, ch := range pattern {
		found := false
		for textIdx < len(text) {
			if rune(text[textIdx]) == ch {
				found = true
				textIdx++
				break
			}
			textIdx++
		}
		if !found {
			return false
		}
	}
	return true
}

// createSSHKeyAutocomplete creates an autocomplete function for SSH key file paths
func (sf *ServerForm) createSSHKeyAutocomplete() func(string) []string {
	return func(currentText string) []string {
		if currentText == "" {
			// Show available keys when field is empty
			availableKeys := GetAvailableSSHKeys()
			if len(availableKeys) == 0 {
				return nil
			}
			return availableKeys
		}

		// Split by comma to handle multiple keys
		keys := strings.Split(currentText, ",")
		lastKey := strings.TrimSpace(keys[len(keys)-1])

		// If the last key is empty (after a comma and space), show all available keys
		if lastKey == "" {
			availableKeys := GetAvailableSSHKeys()
			if len(availableKeys) == 0 {
				return nil
			}
			// Build suggestions with existing keys
			var suggestions []string
			prefix := ""
			if len(keys) > 1 {
				// Join all keys except the last empty one
				existingKeys := keys[:len(keys)-1]
				for i := range existingKeys {
					existingKeys[i] = strings.TrimSpace(existingKeys[i])
				}
				prefix = strings.Join(existingKeys, ", ") + ", "
			}
			for _, key := range availableKeys {
				suggestions = append(suggestions, prefix+key)
			}
			return suggestions
		}

		// Get available keys and filter based on what's being typed
		availableKeys := GetAvailableSSHKeys()
		if len(availableKeys) == 0 {
			return nil
		}

		// Convert to lowercase for case-insensitive matching
		searchTerm := strings.ToLower(lastKey)

		// Filter available keys
		var filtered []string
		prefix := ""
		if len(keys) > 1 {
			// Join all keys except the last one being typed
			existingKeys := keys[:len(keys)-1]
			for i := range existingKeys {
				existingKeys[i] = strings.TrimSpace(existingKeys[i])
			}
			prefix = strings.Join(existingKeys, ", ") + ", "
		}

		for _, key := range availableKeys {
			lowerKey := strings.ToLower(key)
			// Check if the key matches the search term
			if strings.Contains(lowerKey, searchTerm) || matchesSequence(lowerKey, searchTerm) {
				filtered = append(filtered, prefix+key)
			}
		}

		// If no matches found, return nil to allow Tab navigation
		if len(filtered) == 0 {
			return nil
		}

		return filtered
	}
}

// createKnownHostsAutocomplete creates an autocomplete function for known_hosts file paths
func (sf *ServerForm) createKnownHostsAutocomplete() func(string) []string {
	return func(currentText string) []string {
		if currentText == "" {
			// Show available known_hosts files when field is empty
			availableFiles := GetAvailableKnownHostsFiles()
			if len(availableFiles) == 0 {
				return nil
			}
			return availableFiles
		}

		// Split by space to handle multiple files
		files := strings.Split(currentText, " ")
		lastFile := strings.TrimSpace(files[len(files)-1])

		// If the last file is empty (after a space), show all available files
		if lastFile == "" {
			availableFiles := GetAvailableKnownHostsFiles()
			if len(availableFiles) == 0 {
				return nil
			}
			// Build suggestions with existing files
			var suggestions []string
			prefix := ""
			if len(files) > 1 {
				// Join all files except the last empty one
				existingFiles := files[:len(files)-1]
				for i := range existingFiles {
					existingFiles[i] = strings.TrimSpace(existingFiles[i])
				}
				prefix = strings.Join(existingFiles, " ") + " "
			}
			for _, file := range availableFiles {
				suggestions = append(suggestions, prefix+file)
			}
			return suggestions
		}

		// Get available files and filter based on what's being typed
		availableFiles := GetAvailableKnownHostsFiles()
		if len(availableFiles) == 0 {
			return nil
		}

		// Convert to lowercase for case-insensitive matching
		searchTerm := strings.ToLower(lastFile)

		// Filter available files
		var filtered []string
		prefix := ""
		if len(files) > 1 {
			// Join all files except the last one being typed
			existingFiles := files[:len(files)-1]
			for i := range existingFiles {
				existingFiles[i] = strings.TrimSpace(existingFiles[i])
			}
			prefix = strings.Join(existingFiles, " ") + " "
		}

		for _, file := range availableFiles {
			lowerFile := strings.ToLower(file)
			// Check if the file matches the search term
			if strings.Contains(lowerFile, searchTerm) || matchesSequence(lowerFile, searchTerm) {
				filtered = append(filtered, prefix+file)
			}
		}

		// If no matches found, return nil to allow Tab navigation
		if len(filtered) == 0 {
			return nil
		}

		return filtered
	}
}

// createAlgorithmAutocomplete creates an autocomplete function for algorithm input fields
func (sf *ServerForm) createAlgorithmAutocomplete(suggestions []string) func(string) []string {
	return func(currentText string) []string {
		if currentText == "" {
			// Return nil when empty to disable autocomplete, allowing Tab to navigate
			return nil
		}

		// Find the current word being typed
		words := strings.Split(currentText, ",")
		lastWord := strings.TrimSpace(words[len(words)-1])

		// If the last word is empty (after a comma), return nil to allow Tab navigation
		if lastWord == "" {
			return nil
		}

		// Handle prefix characters
		prefix := ""
		searchTerm := lastWord
		if lastWord[0] == '+' || lastWord[0] == '-' || lastWord[0] == '^' {
			prefix = string(lastWord[0])
			if len(lastWord) > 1 {
				searchTerm = lastWord[1:]
			} else {
				// Just a prefix character, show all suggestions
				searchTerm = ""
			}
		}

		// Filter suggestions - check if all characters appear in sequence
		var filtered []string
		for _, s := range suggestions {
			if searchTerm == "" || matchesSequence(strings.ToLower(s), strings.ToLower(searchTerm)) {
				// Build the complete text with the suggestion
				newWords := make([]string, len(words)-1)
				copy(newWords, words[:len(words)-1])
				newWords = append(newWords, prefix+s)
				filtered = append(filtered, strings.Join(newWords, ","))
			}
		}

		// If no matches found, return nil to allow Tab navigation
		if len(filtered) == 0 {
			return nil
		}

		return filtered
	}
}

// validateField validates a single field and updates the validation state
func (sf *ServerForm) validateField(fieldName, value string) string {
	fieldValidators := GetFieldValidators()
	validator, exists := fieldValidators[fieldName]
	if !exists {
		// No validator for this field, it's valid
		sf.validation.SetError(fieldName, "")
		return ""
	}

	// Check required
	if validator.Required && strings.TrimSpace(value) == "" {
		err := fmt.Sprintf("%s is required", fieldName)
		sf.validation.SetError(fieldName, err)
		return err
	}

	// If field is empty and not required, it's valid
	if value == "" {
		sf.validation.SetError(fieldName, "")
		return ""
	}

	// Check custom validation function
	if validator.Validate != nil {
		if err := validator.Validate(value); err != nil {
			sf.validation.SetError(fieldName, err.Error())
			return err.Error()
		}
	}

	// Check regex pattern
	if validator.Pattern != nil && !validator.Pattern.MatchString(value) {
		sf.validation.SetError(fieldName, validator.Message)
		return validator.Message
	}

	// Field is valid
	sf.validation.SetError(fieldName, "")
	return ""
}

// addDropDownWithHelp adds a dropdown field with help support
func (sf *ServerForm) addDropDownWithHelp(form *tview.Form, label, fieldName string, options []string, initialOption int) {
	dropdown := tview.NewDropDown().
		SetLabel(label).
		SetOptions(options, nil).
		SetCurrentOption(initialOption)

	// Add focus handler to show help
	dropdown.SetFocusFunc(func() {
		sf.updateHelp(fieldName)
	})

	form.AddFormItem(dropdown)
}

// addInputFieldWithHelp adds a regular input field with help support
func (sf *ServerForm) addInputFieldWithHelp(form *tview.Form, label, fieldName, defaultValue string, width int, placeholder string) *tview.InputField {
	field := tview.NewInputField().
		SetLabel(label).
		SetText(defaultValue).
		SetFieldWidth(width)

	if placeholder != "" {
		field.SetPlaceholder(placeholder)
	}

	// Add focus handler to show help
	field.SetFocusFunc(func() {
		sf.updateHelp(fieldName)
	})

	form.AddFormItem(field)
	return field
}

// addValidatedInputField adds an input field with real-time validation
func (sf *ServerForm) addValidatedInputField(form *tview.Form, label, fieldName, defaultValue string, width int, placeholder string) *tview.InputField {
	// Store the original label without color tags
	originalLabel := label

	field := tview.NewInputField().
		SetLabel(label).
		SetText(defaultValue).
		SetFieldWidth(width)

	if placeholder != "" {
		field.SetPlaceholder(placeholder)
	}

	// Add change handler for real-time validation
	field.SetChangedFunc(func(text string) {
		if err := sf.validateField(fieldName, text); err != "" {
			// Show error in the label with red color
			field.SetLabel(fmt.Sprintf("[red]%s[-]", originalLabel))
		} else {
			// Clear error indication, restore original label
			field.SetLabel(originalLabel)
		}
	})

	// Add focus handler to show help
	field.SetFocusFunc(func() {
		sf.updateHelp(fieldName)
	})

	// Validate on blur (when field loses focus)
	field.SetFinishedFunc(func(key tcell.Key) {
		sf.validateField(fieldName, field.GetText())
	})

	form.AddFormItem(field)
	return field
}

// validateAllFields validates all fields in the current form
func (sf *ServerForm) validateAllFields() bool {
	// Clear all previous errors first
	sf.validation = NewValidationState()

	data := sf.getFormData()

	// Validate each field based on form data
	// Don't return early - validate all fields
	sf.validateField("Alias", data.Alias)
	sf.validateField("Host", data.Host)
	sf.validateField("Port", data.Port)
	sf.validateField("User", data.User)
	sf.validateField("Keys", data.Key)
	sf.validateField("Tags", data.Tags)

	// Connection fields
	sf.validateField("ConnectTimeout", data.ConnectTimeout)
	sf.validateField("ConnectionAttempts", data.ConnectionAttempts)
	sf.validateField("ServerAliveInterval", data.ServerAliveInterval)
	sf.validateField("ServerAliveCountMax", data.ServerAliveCountMax)
	sf.validateField("IPQoS", data.IPQoS)
	sf.validateField("BindAddress", data.BindAddress)

	// Port forwarding fields
	sf.validateField("LocalForward", data.LocalForward)
	sf.validateField("RemoteForward", data.RemoteForward)
	sf.validateField("DynamicForward", data.DynamicForward)

	// Authentication fields
	sf.validateField("NumberOfPasswordPrompts", data.NumberOfPasswordPrompts)

	// Advanced fields
	sf.validateField("CanonicalizeMaxDots", data.CanonicalizeMaxDots)
	sf.validateField("EscapeChar", data.EscapeChar)

	// Security fields
	sf.validateField("UserKnownHostsFile", data.UserKnownHostsFile)

	return !sf.validation.HasErrors()
}

// getDefaultValues returns default form values based on mode
func (sf *ServerForm) getDefaultValues() ServerFormData {
	if sf.mode == ServerFormEdit && sf.original != nil {
		return ServerFormData{
			Alias:                sf.original.Alias,
			Host:                 sf.original.Host,
			User:                 sf.original.User,
			Port:                 fmt.Sprint(sf.original.Port),
			Key:                  strings.Join(sf.original.IdentityFiles, ", "),
			Tags:                 strings.Join(sf.original.Tags, ", "),
			ProxyJump:            sf.original.ProxyJump,
			ProxyCommand:         sf.original.ProxyCommand,
			RemoteCommand:        sf.original.RemoteCommand,
			RequestTTY:           sf.original.RequestTTY,
			SessionType:          sf.original.SessionType,
			ConnectTimeout:       sf.original.ConnectTimeout,
			ConnectionAttempts:   sf.original.ConnectionAttempts,
			BindAddress:          sf.original.BindAddress,
			BindInterface:        sf.original.BindInterface,
			AddressFamily:        sf.original.AddressFamily,
			ExitOnForwardFailure: sf.original.ExitOnForwardFailure,
			IPQoS:                sf.original.IPQoS,
			// Hostname canonicalization
			CanonicalizeHostname:        sf.original.CanonicalizeHostname,
			CanonicalDomains:            sf.original.CanonicalDomains,
			CanonicalizeFallbackLocal:   sf.original.CanonicalizeFallbackLocal,
			CanonicalizeMaxDots:         sf.original.CanonicalizeMaxDots,
			CanonicalizePermittedCNAMEs: sf.original.CanonicalizePermittedCNAMEs,
			GatewayPorts:                sf.original.GatewayPorts,
			LocalForward:                strings.Join(sf.original.LocalForward, ", "),
			RemoteForward:               strings.Join(sf.original.RemoteForward, ", "),
			DynamicForward:              strings.Join(sf.original.DynamicForward, ", "),
			ClearAllForwardings:         sf.original.ClearAllForwardings,
			// Public key
			PubkeyAuthentication: sf.original.PubkeyAuthentication,
			IdentitiesOnly:       sf.original.IdentitiesOnly,
			// SSH Agent
			AddKeysToAgent: sf.original.AddKeysToAgent,
			IdentityAgent:  sf.original.IdentityAgent,
			// Password & Interactive
			PasswordAuthentication:       sf.original.PasswordAuthentication,
			KbdInteractiveAuthentication: sf.original.KbdInteractiveAuthentication,
			NumberOfPasswordPrompts:      sf.original.NumberOfPasswordPrompts,
			// Advanced
			PreferredAuthentications:    sf.original.PreferredAuthentications,
			ForwardAgent:                sf.original.ForwardAgent,
			ForwardX11:                  sf.original.ForwardX11,
			ForwardX11Trusted:           sf.original.ForwardX11Trusted,
			ControlMaster:               sf.original.ControlMaster,
			ControlPath:                 sf.original.ControlPath,
			ControlPersist:              sf.original.ControlPersist,
			ServerAliveInterval:         sf.original.ServerAliveInterval,
			ServerAliveCountMax:         sf.original.ServerAliveCountMax,
			Compression:                 sf.original.Compression,
			TCPKeepAlive:                sf.original.TCPKeepAlive,
			BatchMode:                   sf.original.BatchMode,
			StrictHostKeyChecking:       sf.original.StrictHostKeyChecking,
			UserKnownHostsFile:          sf.original.UserKnownHostsFile,
			HostKeyAlgorithms:           sf.original.HostKeyAlgorithms,
			PubkeyAcceptedAlgorithms:    sf.original.PubkeyAcceptedAlgorithms,
			HostbasedAcceptedAlgorithms: sf.original.HostbasedAcceptedAlgorithms,
			MACs:                        sf.original.MACs,
			Ciphers:                     sf.original.Ciphers,
			KexAlgorithms:               sf.original.KexAlgorithms,
			VerifyHostKeyDNS:            sf.original.VerifyHostKeyDNS,
			UpdateHostKeys:              sf.original.UpdateHostKeys,
			HashKnownHosts:              sf.original.HashKnownHosts,
			VisualHostKey:               sf.original.VisualHostKey,
			LocalCommand:                sf.original.LocalCommand,
			PermitLocalCommand:          sf.original.PermitLocalCommand,
			EscapeChar:                  sf.original.EscapeChar,
			SendEnv:                     strings.Join(sf.original.SendEnv, ", "),
			SetEnv:                      strings.Join(sf.original.SetEnv, ", "),
			LogLevel:                    sf.original.LogLevel,
		}
	}
	// For new servers, use empty values instead of SSH defaults
	// SSH defaults will be applied by the SSH client if values are not specified
	return ServerFormData{
		Alias: "",   // Explicitly empty for new servers
		Host:  "",   // Explicitly empty for new servers
		User:  "",   // Empty for new servers (SSH will use current username)
		Port:  "22", // Keep port 22 as it's the standard SSH port
		Key:   "",   // Empty for new servers (SSH will try default keys)
		Tags:  "",

		// All other fields should be empty for new servers
		// The SSH client will use its defaults when these are not specified
		ProxyJump:            "",
		ProxyCommand:         "",
		RemoteCommand:        "",
		RequestTTY:           "",
		SessionType:          "",
		ConnectTimeout:       "",
		ConnectionAttempts:   "",
		BindAddress:          "",
		BindInterface:        "",
		AddressFamily:        "",
		ExitOnForwardFailure: "",
		IPQoS:                "",

		// Hostname canonicalization
		CanonicalizeHostname:        "",
		CanonicalDomains:            "",
		CanonicalizeFallbackLocal:   "",
		CanonicalizeMaxDots:         "",
		CanonicalizePermittedCNAMEs: "",

		// Port forwarding
		LocalForward:        "",
		RemoteForward:       "",
		DynamicForward:      "",
		ClearAllForwardings: "",
		GatewayPorts:        "",

		// Authentication
		PubkeyAuthentication:         "",
		IdentitiesOnly:               "",
		AddKeysToAgent:               "",
		IdentityAgent:                "",
		PasswordAuthentication:       "",
		KbdInteractiveAuthentication: "",
		NumberOfPasswordPrompts:      "",
		PreferredAuthentications:     "",
		PubkeyAcceptedAlgorithms:     "",
		HostbasedAcceptedAlgorithms:  "",

		// Forwarding
		ForwardAgent:      "",
		ForwardX11:        "",
		ForwardX11Trusted: "",

		// Multiplexing
		ControlMaster:  "",
		ControlPath:    "",
		ControlPersist: "",

		// Keep-alive
		ServerAliveInterval: "",
		ServerAliveCountMax: "",
		TCPKeepAlive:        "",

		// Connection
		Compression: "",
		BatchMode:   "",

		// Security
		StrictHostKeyChecking: "",
		CheckHostIP:           "",
		FingerprintHash:       "",
		UserKnownHostsFile:    "",
		HostKeyAlgorithms:     "",
		MACs:                  "",
		Ciphers:               "",
		KexAlgorithms:         "",
		VerifyHostKeyDNS:      "",
		UpdateHostKeys:        "",
		HashKnownHosts:        "",
		VisualHostKey:         "",

		// Command execution
		LocalCommand:       "",
		PermitLocalCommand: "",
		EscapeChar:         "",

		// Environment
		SendEnv: "",
		SetEnv:  "",

		// Debugging
		LogLevel: "",
	}
}

// createBasicForm creates the Basic configuration tab
func (sf *ServerForm) createBasicForm() {
	form := tview.NewForm()
	defaultValues := sf.getDefaultValues()

	// Add validated input fields
	sf.addValidatedInputField(form, "Alias:", "Alias", defaultValues.Alias, 20, GetFieldPlaceholder("Alias"))
	sf.addValidatedInputField(form, "Host/IP:", "Host", defaultValues.Host, 20, GetFieldPlaceholder("Host"))
	sf.addValidatedInputField(form, "User:", "User", defaultValues.User, 20, GetFieldPlaceholder("User"))
	sf.addValidatedInputField(form, "Port:", "Port", defaultValues.Port, 20, GetFieldPlaceholder("Port"))

	// Keys field with autocomplete
	keysField := sf.addValidatedInputField(form, "Keys:", "Keys", defaultValues.Key, 40, GetFieldPlaceholder("Keys"))
	keysField.SetAutocompleteFunc(sf.createSSHKeyAutocomplete())

	// Tags field
	sf.addValidatedInputField(form, "Tags:", "Tags", defaultValues.Tags, 30, GetFieldPlaceholder("Tags"))

	// Add save and cancel buttons
	form.AddButton("Save", sf.handleSaveButton)
	form.AddButton("Cancel", sf.handleCancel)

	// Set up form-level input capture for shortcuts
	sf.setupFormShortcuts(form)

	sf.forms["Basic"] = form
	sf.pages.AddPage("Basic", form, true, true)
}

// createConnectionForm creates the Connection & Proxy tab
func (sf *ServerForm) createConnectionForm() {
	form := tview.NewForm()
	defaultValues := sf.getDefaultValues()

	form.AddTextView("\n[yellow]▶ Proxy & Command[-]", "", 0, 1, true, false)
	sf.addInputFieldWithHelp(form, "ProxyJump:", "ProxyJump", defaultValues.ProxyJump, 40, GetFieldPlaceholder("ProxyJump"))
	sf.addInputFieldWithHelp(form, "ProxyCommand:", "ProxyCommand", defaultValues.ProxyCommand, 40, GetFieldPlaceholder("ProxyCommand"))
	sf.addInputFieldWithHelp(form, "RemoteCommand:", "RemoteCommand", defaultValues.RemoteCommand, 40, GetFieldPlaceholder("RemoteCommand"))

	// RequestTTY dropdown
	requestTTYOptions := createOptionsWithDefault("RequestTTY", []string{"", "yes", "no", "force", "auto"})
	requestTTYIndex := sf.findOptionIndex(requestTTYOptions, defaultValues.RequestTTY)
	sf.addDropDownWithHelp(form, "RequestTTY:", "RequestTTY", requestTTYOptions, requestTTYIndex)

	// SessionType dropdown (OpenSSH 8.7+)
	sessionTypeOptions := createOptionsWithDefault("SessionType", []string{"", "none (-N)", "subsystem (-s)", "default"})
	sessionTypeIndex := sf.findOptionIndex(sessionTypeOptions, defaultValues.SessionType)
	sf.addDropDownWithHelp(form, "SessionType:", "SessionType", sessionTypeOptions, sessionTypeIndex)

	form.AddTextView("\n[yellow]▶ Connection Settings[-]", "", 0, 1, true, false)
	sf.addValidatedInputField(form, "ConnectTimeout:", "ConnectTimeout", defaultValues.ConnectTimeout, 10, GetFieldPlaceholder("ConnectTimeout"))
	sf.addValidatedInputField(form, "ConnectionAttempts:", "ConnectionAttempts", defaultValues.ConnectionAttempts, 10, GetFieldPlaceholder("ConnectionAttempts"))
	sf.addValidatedInputField(form, "IPQoS:", "IPQoS", defaultValues.IPQoS, 20, GetFieldPlaceholder("IPQoS"))

	// BatchMode dropdown (moved from Keep-Alive)
	batchModeOptions := createOptionsWithDefault("BatchMode", []string{"", "yes", "no"})
	batchModeIndex := sf.findOptionIndex(batchModeOptions, defaultValues.BatchMode)
	sf.addDropDownWithHelp(form, "BatchMode:", "BatchMode", batchModeOptions, batchModeIndex)

	form.AddTextView("\n[yellow]▶ Bind Options[-]", "", 0, 1, true, false)
	sf.addValidatedInputField(form, "BindAddress:", "BindAddress", defaultValues.BindAddress, 40, GetFieldPlaceholder("BindAddress"))

	// BindInterface dropdown with available network interfaces
	interfaceOptions := append([]string{""}, GetNetworkInterfaces()...)
	bindInterfaceIndex := sf.findOptionIndex(interfaceOptions, defaultValues.BindInterface)
	sf.addDropDownWithHelp(form, "BindInterface:", "BindInterface", interfaceOptions, bindInterfaceIndex)

	// AddressFamily dropdown
	addressFamilyOptions := createOptionsWithDefault("AddressFamily", []string{"", "any", "inet", "inet6"})
	addressFamilyIndex := sf.findOptionIndex(addressFamilyOptions, defaultValues.AddressFamily)
	sf.addDropDownWithHelp(form, "AddressFamily:", "AddressFamily", addressFamilyOptions, addressFamilyIndex)

	form.AddTextView("\n[yellow]▶ Hostname Canonicalization[-]", "", 0, 1, true, false)

	// CanonicalizeHostname dropdown
	canonicalizeOptions := createOptionsWithDefault("CanonicalizeHostname", []string{"", "yes", "no", "always"})
	canonicalizeIndex := sf.findOptionIndex(canonicalizeOptions, defaultValues.CanonicalizeHostname)
	sf.addDropDownWithHelp(form, "CanonicalizeHostname:", "CanonicalizeHostname", canonicalizeOptions, canonicalizeIndex)

	sf.addInputFieldWithHelp(form, "CanonicalDomains:", "CanonicalDomains", defaultValues.CanonicalDomains, 40, GetFieldPlaceholder("CanonicalDomains"))

	// CanonicalizeFallbackLocal dropdown
	fallbackOptions := createOptionsWithDefault("CanonicalizeFallbackLocal", []string{"", "yes", "no"})
	fallbackIndex := sf.findOptionIndex(fallbackOptions, defaultValues.CanonicalizeFallbackLocal)
	sf.addDropDownWithHelp(form, "CanonicalizeFallbackLocal:", "CanonicalizeFallbackLocal", fallbackOptions, fallbackIndex)

	sf.addValidatedInputField(form, "CanonicalizeMaxDots:", "CanonicalizeMaxDots", defaultValues.CanonicalizeMaxDots, 10, GetFieldPlaceholder("CanonicalizeMaxDots"))

	sf.addInputFieldWithHelp(form, "CanonicalizePermittedCNAMEs:", "CanonicalizePermittedCNAMEs", defaultValues.CanonicalizePermittedCNAMEs, 40, GetFieldPlaceholder("CanonicalizePermittedCNAMEs"))

	form.AddTextView("\n[yellow]▶ Keep-Alive[-]", "", 0, 1, true, false)
	sf.addValidatedInputField(form, "ServerAliveInterval:", "ServerAliveInterval", defaultValues.ServerAliveInterval, 10, GetFieldPlaceholder("ServerAliveInterval"))
	sf.addValidatedInputField(form, "ServerAliveCountMax:", "ServerAliveCountMax", defaultValues.ServerAliveCountMax, 10, GetFieldPlaceholder("ServerAliveCountMax"))

	// Compression dropdown
	compressionOptions := createOptionsWithDefault("Compression", []string{"", "yes", "no"})
	compressionIndex := sf.findOptionIndex(compressionOptions, defaultValues.Compression)
	sf.addDropDownWithHelp(form, "Compression:", "Compression", compressionOptions, compressionIndex)

	// TCPKeepAlive dropdown
	tcpKeepAliveOptions := createOptionsWithDefault("TCPKeepAlive", []string{"", "yes", "no"})
	tcpKeepAliveIndex := sf.findOptionIndex(tcpKeepAliveOptions, defaultValues.TCPKeepAlive)
	sf.addDropDownWithHelp(form, "TCPKeepAlive:", "TCPKeepAlive", tcpKeepAliveOptions, tcpKeepAliveIndex)

	form.AddTextView("\n[yellow]▶ Multiplexing[-]", "", 0, 1, true, false)
	// ControlMaster dropdown
	controlMasterOptions := createOptionsWithDefault("ControlMaster", []string{"", "yes", "no", "auto", "ask", "autoask"})
	controlMasterIndex := sf.findOptionIndex(controlMasterOptions, defaultValues.ControlMaster)
	sf.addDropDownWithHelp(form, "ControlMaster:", "ControlMaster", controlMasterOptions, controlMasterIndex)
	sf.addInputFieldWithHelp(form, "ControlPath:", "ControlPath", defaultValues.ControlPath, 40, GetFieldPlaceholder("ControlPath"))
	sf.addInputFieldWithHelp(form, "ControlPersist:", "ControlPersist", defaultValues.ControlPersist, 20, GetFieldPlaceholder("ControlPersist"))

	// Add save and cancel buttons
	form.AddButton("Save", sf.handleSaveButton)
	form.AddButton("Cancel", sf.handleCancel)

	// Set up form-level input capture for shortcuts
	sf.setupFormShortcuts(form)

	sf.forms["Connection"] = form
	sf.pages.AddPage("Connection", form, true, false)
}

// createForwardingForm creates the Port Forwarding tab
func (sf *ServerForm) createForwardingForm() {
	form := tview.NewForm()
	defaultValues := sf.getDefaultValues()

	form.AddTextView("\n[yellow]▶ Port Forwarding[-]", "", 0, 1, true, false)
	sf.addValidatedInputField(form, "LocalForward:", "LocalForward", defaultValues.LocalForward, 40, GetFieldPlaceholder("LocalForward"))
	sf.addValidatedInputField(form, "RemoteForward:", "RemoteForward", defaultValues.RemoteForward, 40, GetFieldPlaceholder("RemoteForward"))
	sf.addValidatedInputField(form, "DynamicForward:", "DynamicForward", defaultValues.DynamicForward, 40, GetFieldPlaceholder("DynamicForward"))

	// ClearAllForwardings dropdown
	clearAllForwardingsOptions := createOptionsWithDefault("ClearAllForwardings", []string{"", "yes", "no"})
	clearAllForwardingsIndex := sf.findOptionIndex(clearAllForwardingsOptions, defaultValues.ClearAllForwardings)
	sf.addDropDownWithHelp(form, "ClearAllForwardings:", "ClearAllForwardings", clearAllForwardingsOptions, clearAllForwardingsIndex)

	// ExitOnForwardFailure dropdown
	exitOnForwardFailureOptions := createOptionsWithDefault("ExitOnForwardFailure", []string{"", "yes", "no"})
	exitOnForwardFailureIndex := sf.findOptionIndex(exitOnForwardFailureOptions, defaultValues.ExitOnForwardFailure)
	sf.addDropDownWithHelp(form, "ExitOnForwardFailure:", "ExitOnForwardFailure", exitOnForwardFailureOptions, exitOnForwardFailureIndex)

	// GatewayPorts dropdown
	gatewayPortsOptions := createOptionsWithDefault("GatewayPorts", []string{"", "yes", "no", "clientspecified"})
	gatewayPortsIndex := sf.findOptionIndex(gatewayPortsOptions, defaultValues.GatewayPorts)
	sf.addDropDownWithHelp(form, "GatewayPorts:", "GatewayPorts", gatewayPortsOptions, gatewayPortsIndex)

	form.AddTextView("\n[yellow]▶ Agent & X11 Forwarding[-]", "", 0, 1, true, false)

	// ForwardAgent dropdown
	forwardAgentOptions := createOptionsWithDefault("ForwardAgent", []string{"", "yes", "no"})
	forwardAgentIndex := sf.findOptionIndex(forwardAgentOptions, defaultValues.ForwardAgent)
	sf.addDropDownWithHelp(form, "ForwardAgent:", "ForwardAgent", forwardAgentOptions, forwardAgentIndex)

	// ForwardX11 dropdown
	forwardX11Options := createOptionsWithDefault("ForwardX11", []string{"", "yes", "no"})
	forwardX11Index := sf.findOptionIndex(forwardX11Options, defaultValues.ForwardX11)
	sf.addDropDownWithHelp(form, "ForwardX11:", "ForwardX11", forwardX11Options, forwardX11Index)

	// ForwardX11Trusted dropdown
	forwardX11TrustedOptions := createOptionsWithDefault("ForwardX11Trusted", []string{"", "yes", "no"})
	forwardX11TrustedIndex := sf.findOptionIndex(forwardX11TrustedOptions, defaultValues.ForwardX11Trusted)
	sf.addDropDownWithHelp(form, "ForwardX11Trusted:", "ForwardX11Trusted", forwardX11TrustedOptions, forwardX11TrustedIndex)

	// Add save and cancel buttons
	form.AddButton("Save", sf.handleSaveButton)
	form.AddButton("Cancel", sf.handleCancel)

	// Set up form-level input capture for shortcuts
	sf.setupFormShortcuts(form)

	sf.forms["Forwarding"] = form
	sf.pages.AddPage("Forwarding", form, true, false)
}

// Algorithm suggestions for autocomplete
var (
	pubkeyAlgorithms = []string{
		"ssh-ed25519", "ssh-ed25519-cert-v01@openssh.com",
		"sk-ssh-ed25519@openssh.com", "sk-ssh-ed25519-cert-v01@openssh.com",
		"ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521",
		"ecdsa-sha2-nistp256-cert-v01@openssh.com",
		"ecdsa-sha2-nistp384-cert-v01@openssh.com",
		"ecdsa-sha2-nistp521-cert-v01@openssh.com",
		"sk-ecdsa-sha2-nistp256@openssh.com",
		"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com",
		"rsa-sha2-512", "rsa-sha2-256",
		"rsa-sha2-512-cert-v01@openssh.com",
		"rsa-sha2-256-cert-v01@openssh.com",
		"ssh-rsa", "ssh-rsa-cert-v01@openssh.com",
		"ssh-dss", "ssh-dss-cert-v01@openssh.com",
	}

	cipherAlgorithms = []string{
		"aes128-ctr", "aes192-ctr", "aes256-ctr",
		"aes128-gcm@openssh.com", "aes256-gcm@openssh.com",
		"chacha20-poly1305@openssh.com",
		"aes128-cbc", "aes192-cbc", "aes256-cbc", "3des-cbc",
	}

	macAlgorithms = []string{
		"hmac-sha2-256", "hmac-sha2-512",
		"hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com",
		"umac-64@openssh.com", "umac-128@openssh.com",
		"umac-64-etm@openssh.com", "umac-128-etm@openssh.com",
		"hmac-sha1", "hmac-sha1-96",
		"hmac-sha1-etm@openssh.com", "hmac-sha1-96-etm@openssh.com",
		"hmac-md5", "hmac-md5-96",
		"hmac-md5-etm@openssh.com", "hmac-md5-96-etm@openssh.com",
	}

	kexAlgorithms = []string{
		"curve25519-sha256", "curve25519-sha256@libssh.org",
		"ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521",
		"diffie-hellman-group-exchange-sha256",
		"diffie-hellman-group16-sha512", "diffie-hellman-group18-sha512",
		"diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1",
		"diffie-hellman-group-exchange-sha1",
		"diffie-hellman-group1-sha1",
	}

	hostKeyAlgorithms = []string{
		"ssh-ed25519", "ssh-ed25519-cert-v01@openssh.com",
		"sk-ssh-ed25519@openssh.com", "sk-ssh-ed25519-cert-v01@openssh.com",
		"ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521",
		"ecdsa-sha2-nistp256-cert-v01@openssh.com",
		"ecdsa-sha2-nistp384-cert-v01@openssh.com",
		"ecdsa-sha2-nistp521-cert-v01@openssh.com",
		"rsa-sha2-512", "rsa-sha2-256",
		"rsa-sha2-512-cert-v01@openssh.com",
		"rsa-sha2-256-cert-v01@openssh.com",
		"ssh-rsa", "ssh-rsa-cert-v01@openssh.com",
		"ssh-dss", "ssh-dss-cert-v01@openssh.com",
	}
)

// createAuthenticationForm creates the Authentication tab
func (sf *ServerForm) createAuthenticationForm() {
	form := tview.NewForm()
	defaultValues := sf.getDefaultValues()

	// Most common: Public key authentication
	form.AddTextView("\n[yellow]▶ Public Key Authentication[-]", "", 0, 1, true, false)

	// PubkeyAuthentication dropdown
	pubkeyOptions := createOptionsWithDefault("PubkeyAuthentication", []string{"", "yes", "no"})
	pubkeyIndex := sf.findOptionIndex(pubkeyOptions, defaultValues.PubkeyAuthentication)
	sf.addDropDownWithHelp(form, "PubkeyAuthentication:", "PubkeyAuthentication", pubkeyOptions, pubkeyIndex)

	// IdentitiesOnly dropdown - controls whether to use only specified identity files
	identitiesOnlyOptions := createOptionsWithDefault("IdentitiesOnly", []string{"", "yes", "no"})
	identitiesOnlyIndex := sf.findOptionIndex(identitiesOnlyOptions, defaultValues.IdentitiesOnly)
	sf.addDropDownWithHelp(form, "IdentitiesOnly:", "IdentitiesOnly", identitiesOnlyOptions, identitiesOnlyIndex)

	// SSH Agent settings
	form.AddTextView("\n[yellow]▶ SSH Agent[-]", "", 0, 1, true, false)

	// AddKeysToAgent dropdown
	addKeysOptions := createOptionsWithDefault("AddKeysToAgent", []string{"", "yes", "no", "ask", "confirm"})
	addKeysIndex := sf.findOptionIndex(addKeysOptions, defaultValues.AddKeysToAgent)
	sf.addDropDownWithHelp(form, "AddKeysToAgent:", "AddKeysToAgent", addKeysOptions, addKeysIndex)

	sf.addInputFieldWithHelp(form, "IdentityAgent:", "IdentityAgent", defaultValues.IdentityAgent, 40, GetFieldPlaceholder("IdentityAgent"))

	// Password/Interactive authentication
	form.AddTextView("\n[yellow]▶ Password & Interactive[-]", "", 0, 1, true, false)

	// PasswordAuthentication dropdown
	passwordOptions := createOptionsWithDefault("PasswordAuthentication", []string{"", "yes", "no"})
	passwordIndex := sf.findOptionIndex(passwordOptions, defaultValues.PasswordAuthentication)
	sf.addDropDownWithHelp(form, "PasswordAuthentication:", "PasswordAuthentication", passwordOptions, passwordIndex)

	// KbdInteractiveAuthentication dropdown
	kbdInteractiveOptions := createOptionsWithDefault("KbdInteractiveAuthentication", []string{"", "yes", "no"})
	kbdInteractiveIndex := sf.findOptionIndex(kbdInteractiveOptions, defaultValues.KbdInteractiveAuthentication)
	sf.addDropDownWithHelp(form, "KbdInteractiveAuthentication:", "KbdInteractiveAuthentication", kbdInteractiveOptions, kbdInteractiveIndex)

	// NumberOfPasswordPrompts field
	sf.addValidatedInputField(form, "NumberOfPasswordPrompts:", "NumberOfPasswordPrompts", defaultValues.NumberOfPasswordPrompts, 10, GetFieldPlaceholder("NumberOfPasswordPrompts"))

	// Advanced: Authentication order preference
	form.AddTextView("\n[yellow]▶ Advanced[-]", "", 0, 1, true, false)

	sf.addInputFieldWithHelp(form, "PreferredAuthentications:", "PreferredAuthentications", defaultValues.PreferredAuthentications, 40, GetFieldPlaceholder("PreferredAuthentications"))

	// PubkeyAcceptedAlgorithms with autocomplete support (moved from Advanced/Cryptography)
	pubkeyAlgField := sf.addInputFieldWithHelp(form, "PubkeyAcceptedAlgorithms:", "PubkeyAcceptedAlgorithms", defaultValues.PubkeyAcceptedAlgorithms, 40, GetFieldPlaceholder("PubkeyAcceptedAlgorithms"))
	pubkeyAlgField.SetAutocompleteFunc(sf.createAlgorithmAutocomplete(pubkeyAlgorithms))

	// HostbasedAcceptedAlgorithms with autocomplete support (moved from Advanced/Cryptography)
	hostbasedAlgField := sf.addInputFieldWithHelp(form, "HostbasedAcceptedAlgorithms:", "HostbasedAcceptedAlgorithms", defaultValues.HostbasedAcceptedAlgorithms, 40, GetFieldPlaceholder("HostbasedAcceptedAlgorithms"))
	hostbasedAlgField.SetAutocompleteFunc(sf.createAlgorithmAutocomplete(pubkeyAlgorithms))

	// Add save and cancel buttons
	form.AddButton("Save", sf.handleSaveButton)
	form.AddButton("Cancel", sf.handleCancel)

	// Set up form-level input capture for shortcuts
	sf.setupFormShortcuts(form)

	sf.forms["Authentication"] = form
	sf.pages.AddPage("Authentication", form, true, false)
}

// createAdvancedForm creates the Advanced settings tab
func (sf *ServerForm) createAdvancedForm() {
	form := tview.NewForm()
	defaultValues := sf.getDefaultValues()

	form.AddTextView("\n[yellow]▶ Security[-]", "", 0, 1, true, false)

	// StrictHostKeyChecking dropdown
	strictHostKeyOptions := createOptionsWithDefault("StrictHostKeyChecking", []string{"", "yes", "no", "ask", "accept-new"})
	strictHostKeyIndex := sf.findOptionIndex(strictHostKeyOptions, defaultValues.StrictHostKeyChecking)
	sf.addDropDownWithHelp(form, "StrictHostKeyChecking:", "StrictHostKeyChecking", strictHostKeyOptions, strictHostKeyIndex)

	// CheckHostIP dropdown
	checkHostIPOptions := createOptionsWithDefault("CheckHostIP", []string{"", "yes", "no"})
	checkHostIPIndex := sf.findOptionIndex(checkHostIPOptions, defaultValues.CheckHostIP)
	sf.addDropDownWithHelp(form, "CheckHostIP:", "CheckHostIP", checkHostIPOptions, checkHostIPIndex)

	// FingerprintHash dropdown
	fingerprintHashOptions := createOptionsWithDefault("FingerprintHash", []string{"", "md5", "sha256"})
	fingerprintHashIndex := sf.findOptionIndex(fingerprintHashOptions, defaultValues.FingerprintHash)
	sf.addDropDownWithHelp(form, "FingerprintHash:", "FingerprintHash", fingerprintHashOptions, fingerprintHashIndex)

	// VerifyHostKeyDNS dropdown
	verifyHostKeyDNSOptions := createOptionsWithDefault("VerifyHostKeyDNS", []string{"", "yes", "no", "ask"})
	verifyHostKeyDNSIndex := sf.findOptionIndex(verifyHostKeyDNSOptions, defaultValues.VerifyHostKeyDNS)
	sf.addDropDownWithHelp(form, "VerifyHostKeyDNS:", "VerifyHostKeyDNS", verifyHostKeyDNSOptions, verifyHostKeyDNSIndex)

	// UpdateHostKeys dropdown
	updateHostKeysOptions := createOptionsWithDefault("UpdateHostKeys", []string{"", "yes", "no", "ask"})
	updateHostKeysIndex := sf.findOptionIndex(updateHostKeysOptions, defaultValues.UpdateHostKeys)
	sf.addDropDownWithHelp(form, "UpdateHostKeys:", "UpdateHostKeys", updateHostKeysOptions, updateHostKeysIndex)

	// HashKnownHosts dropdown
	hashKnownHostsOptions := createOptionsWithDefault("HashKnownHosts", []string{"", "yes", "no"})
	hashKnownHostsIndex := sf.findOptionIndex(hashKnownHostsOptions, defaultValues.HashKnownHosts)
	sf.addDropDownWithHelp(form, "HashKnownHosts:", "HashKnownHosts", hashKnownHostsOptions, hashKnownHostsIndex)

	// VisualHostKey dropdown
	visualHostKeyOptions := createOptionsWithDefault("VisualHostKey", []string{"", "yes", "no"})
	visualHostKeyIndex := sf.findOptionIndex(visualHostKeyOptions, defaultValues.VisualHostKey)
	sf.addDropDownWithHelp(form, "VisualHostKey:", "VisualHostKey", visualHostKeyOptions, visualHostKeyIndex)

	// UserKnownHostsFile field with autocomplete and validation
	knownHostsField := sf.addValidatedInputField(form, "UserKnownHostsFile:", "UserKnownHostsFile", defaultValues.UserKnownHostsFile, 40, GetFieldPlaceholder("UserKnownHostsFile"))
	knownHostsField.SetAutocompleteFunc(sf.createKnownHostsAutocomplete())

	form.AddTextView("\n[yellow]▶ Cryptography[-]", "", 0, 1, true, false)

	// Ciphers with autocomplete support
	ciphersField := sf.addInputFieldWithHelp(form, "Ciphers:", "Ciphers", defaultValues.Ciphers, 40, GetFieldPlaceholder("Ciphers"))
	ciphersField.SetAutocompleteFunc(sf.createAlgorithmAutocomplete(cipherAlgorithms))

	// MACs with autocomplete support
	macsField := sf.addInputFieldWithHelp(form, "MACs:", "MACs", defaultValues.MACs, 40, GetFieldPlaceholder("MACs"))
	macsField.SetAutocompleteFunc(sf.createAlgorithmAutocomplete(macAlgorithms))

	// KexAlgorithms with autocomplete support
	kexField := sf.addInputFieldWithHelp(form, "KexAlgorithms:", "KexAlgorithms", defaultValues.KexAlgorithms, 40, GetFieldPlaceholder("KexAlgorithms"))
	kexField.SetAutocompleteFunc(sf.createAlgorithmAutocomplete(kexAlgorithms))

	// HostKeyAlgorithms with autocomplete support
	hostKeyField := sf.addInputFieldWithHelp(form, "HostKeyAlgorithms:", "HostKeyAlgorithms", defaultValues.HostKeyAlgorithms, 40, GetFieldPlaceholder("HostKeyAlgorithms"))
	hostKeyField.SetAutocompleteFunc(sf.createAlgorithmAutocomplete(hostKeyAlgorithms))

	form.AddTextView("\n[yellow]▶ Command Execution[-]", "", 0, 1, true, false)
	sf.addInputFieldWithHelp(form, "LocalCommand:", "LocalCommand", defaultValues.LocalCommand, 40, GetFieldPlaceholder("LocalCommand"))

	// PermitLocalCommand dropdown
	permitLocalCommandOptions := createOptionsWithDefault("PermitLocalCommand", []string{"", "yes", "no"})
	permitLocalCommandIndex := sf.findOptionIndex(permitLocalCommandOptions, defaultValues.PermitLocalCommand)
	sf.addDropDownWithHelp(form, "PermitLocalCommand:", "PermitLocalCommand", permitLocalCommandOptions, permitLocalCommandIndex)

	// EscapeChar input field
	sf.addValidatedInputField(form, "EscapeChar:", "EscapeChar", defaultValues.EscapeChar, 10, GetFieldPlaceholder("EscapeChar"))

	form.AddTextView("\n[yellow]▶ Environment[-]", "", 0, 1, true, false)
	sf.addInputFieldWithHelp(form, "SendEnv:", "SendEnv", defaultValues.SendEnv, 40, GetFieldPlaceholder("SendEnv"))
	sf.addInputFieldWithHelp(form, "SetEnv:", "SetEnv", defaultValues.SetEnv, 40, GetFieldPlaceholder("SetEnv"))

	form.AddTextView("\n[yellow]▶ Debugging[-]", "", 0, 1, true, false)

	// LogLevel dropdown
	logLevelOptions := createOptionsWithDefault("LogLevel", []string{"", "QUIET", "FATAL", "ERROR", "INFO", "VERBOSE", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3"})
	logLevelIndex := sf.findOptionIndex(logLevelOptions, defaultValues.LogLevel)
	sf.addDropDownWithHelp(form, "LogLevel:", "LogLevel", logLevelOptions, logLevelIndex)

	// Add save and cancel buttons
	form.AddButton("Save", sf.handleSaveButton)
	form.AddButton("Cancel", sf.handleCancel)

	// Set up form-level input capture for shortcuts
	sf.setupFormShortcuts(form)

	sf.forms["Advanced"] = form
	sf.pages.AddPage("Advanced", form, true, false)
}

type ServerFormData struct {
	Alias string
	Host  string
	User  string
	Port  string
	Key   string
	Tags  string

	// Connection and proxy settings
	ProxyJump            string
	ProxyCommand         string
	RemoteCommand        string
	RequestTTY           string
	SessionType          string
	ConnectTimeout       string
	ConnectionAttempts   string
	BindAddress          string
	BindInterface        string
	AddressFamily        string
	ExitOnForwardFailure string
	IPQoS                string
	// Hostname canonicalization
	CanonicalizeHostname        string
	CanonicalDomains            string
	CanonicalizeFallbackLocal   string
	CanonicalizeMaxDots         string
	CanonicalizePermittedCNAMEs string

	// Port forwarding
	LocalForward        string
	RemoteForward       string
	DynamicForward      string
	ClearAllForwardings string
	GatewayPorts        string

	// Authentication and key management
	// Public key
	PubkeyAuthentication string
	IdentitiesOnly       string
	// SSH Agent
	AddKeysToAgent string
	IdentityAgent  string
	// Password & Interactive
	PasswordAuthentication       string
	KbdInteractiveAuthentication string
	NumberOfPasswordPrompts      string
	// Advanced
	PreferredAuthentications string

	// Agent and X11 forwarding
	ForwardAgent      string
	ForwardX11        string
	ForwardX11Trusted string

	// Connection multiplexing
	ControlMaster  string
	ControlPath    string
	ControlPersist string

	// Connection reliability
	ServerAliveInterval string
	ServerAliveCountMax string
	Compression         string
	TCPKeepAlive        string
	BatchMode           string

	// Security settings
	StrictHostKeyChecking       string
	CheckHostIP                 string
	FingerprintHash             string
	UserKnownHostsFile          string
	HostKeyAlgorithms           string
	PubkeyAcceptedAlgorithms    string
	HostbasedAcceptedAlgorithms string
	MACs                        string
	Ciphers                     string
	KexAlgorithms               string
	VerifyHostKeyDNS            string
	UpdateHostKeys              string
	HashKnownHosts              string
	VisualHostKey               string

	// Command execution
	LocalCommand       string
	PermitLocalCommand string
	EscapeChar         string

	// Environment settings
	SendEnv string
	SetEnv  string

	// Debugging settings
	LogLevel string
}

// stripColorTags removes tview color tags from a string
// e.g., "[red]Port:[-]" becomes "Port:"
func (sf *ServerForm) getFormData() ServerFormData {
	// Helper function to get text from InputField across all forms
	getFieldText := func(fieldName string) string {
		for _, form := range sf.forms {
			for i := 0; i < form.GetFormItemCount(); i++ {
				if field, ok := form.GetFormItem(i).(*tview.InputField); ok {
					label := strings.TrimSpace(field.GetLabel())
					// Strip color tags from label for comparison
					// Labels can be: "Port:", "[red]Port:[-]", "[green]Port:[-]"
					cleanLabel := stripColorTags(label)
					if strings.HasPrefix(cleanLabel, fieldName) {
						return strings.TrimSpace(field.GetText())
					}
				}
			}
		}
		return ""
	}

	// Helper function to get selected option from DropDown across all forms
	getDropdownValue := func(fieldName string) string {
		for _, form := range sf.forms {
			for i := 0; i < form.GetFormItemCount(); i++ {
				if dropdown, ok := form.GetFormItem(i).(*tview.DropDown); ok {
					label := strings.TrimSpace(dropdown.GetLabel())
					// Strip color tags from label for comparison
					cleanLabel := stripColorTags(label)
					if strings.HasPrefix(cleanLabel, fieldName) {
						_, text := dropdown.GetCurrentOption()
						// Parse the option value to handle "default (value)" format
						return parseOptionValue(text)
					}
				}
			}
		}
		return ""
	}

	return ServerFormData{
		Alias: getFieldText("Alias:"),
		Host:  getFieldText("Host/IP:"),
		User:  getFieldText("User:"),
		Port:  getFieldText("Port:"),
		Key:   getFieldText("Keys:"),
		Tags:  getFieldText("Tags:"),
		// Connection and proxy settings
		ProxyJump:            getFieldText("ProxyJump:"),
		ProxyCommand:         getFieldText("ProxyCommand:"),
		RemoteCommand:        getFieldText("RemoteCommand:"),
		RequestTTY:           getDropdownValue("RequestTTY:"),
		SessionType:          sf.parseSessionType(getDropdownValue("SessionType:")),
		ConnectTimeout:       getFieldText("ConnectTimeout:"),
		ConnectionAttempts:   getFieldText("ConnectionAttempts:"),
		BindAddress:          getFieldText("BindAddress:"),
		BindInterface:        getDropdownValue("BindInterface:"),
		AddressFamily:        getDropdownValue("AddressFamily:"),
		ExitOnForwardFailure: getDropdownValue("ExitOnForwardFailure:"),
		// Port forwarding
		LocalForward:        getFieldText("LocalForward:"),
		RemoteForward:       getFieldText("RemoteForward:"),
		DynamicForward:      getFieldText("DynamicForward:"),
		ClearAllForwardings: getDropdownValue("ClearAllForwardings:"),
		// Authentication and key management
		// Public key
		PubkeyAuthentication: getDropdownValue("PubkeyAuthentication:"),
		IdentitiesOnly:       getDropdownValue("IdentitiesOnly:"),
		// SSH Agent
		AddKeysToAgent: getDropdownValue("AddKeysToAgent:"),
		IdentityAgent:  getFieldText("IdentityAgent:"),
		// Password & Interactive
		PasswordAuthentication:       getDropdownValue("PasswordAuthentication:"),
		KbdInteractiveAuthentication: getDropdownValue("KbdInteractiveAuthentication:"),
		NumberOfPasswordPrompts:      getFieldText("NumberOfPasswordPrompts:"),
		// Advanced
		PreferredAuthentications: getFieldText("PreferredAuthentications:"),
		// Agent and X11 forwarding
		ForwardAgent:      getDropdownValue("ForwardAgent:"),
		ForwardX11:        getDropdownValue("ForwardX11:"),
		ForwardX11Trusted: getDropdownValue("ForwardX11Trusted:"),
		// Connection multiplexing
		ControlMaster:  getDropdownValue("ControlMaster:"),
		ControlPath:    getFieldText("ControlPath:"),
		ControlPersist: getFieldText("ControlPersist:"),
		// Connection reliability settings
		ServerAliveInterval: getFieldText("ServerAliveInterval:"),
		ServerAliveCountMax: getFieldText("ServerAliveCountMax:"),
		Compression:         getDropdownValue("Compression:"),
		TCPKeepAlive:        getDropdownValue("TCPKeepAlive:"),
		BatchMode:           getDropdownValue("BatchMode:"),
		// Security settings
		StrictHostKeyChecking:    getDropdownValue("StrictHostKeyChecking:"),
		UserKnownHostsFile:       getFieldText("UserKnownHostsFile:"),
		HostKeyAlgorithms:        getFieldText("HostKeyAlgorithms:"),
		PubkeyAcceptedAlgorithms: getFieldText("PubkeyAcceptedAlgorithms:"),
		MACs:                     getFieldText("MACs:"),
		Ciphers:                  getFieldText("Ciphers:"),
		KexAlgorithms:            getFieldText("KexAlgorithms:"),
		VerifyHostKeyDNS:         getDropdownValue("VerifyHostKeyDNS:"),
		UpdateHostKeys:           getDropdownValue("UpdateHostKeys:"),
		HashKnownHosts:           getDropdownValue("HashKnownHosts:"),
		VisualHostKey:            getDropdownValue("VisualHostKey:"),
		// Command execution
		LocalCommand:       getFieldText("LocalCommand:"),
		PermitLocalCommand: getDropdownValue("PermitLocalCommand:"),
		EscapeChar:         getFieldText("EscapeChar:"),
		// Environment settings
		SendEnv: getFieldText("SendEnv:"),
		SetEnv:  getFieldText("SetEnv:"),
		// Debugging settings
		LogLevel: getDropdownValue("LogLevel:"),
	}
}

// parseSessionType converts dropdown display value to actual value
func (sf *ServerForm) parseSessionType(value string) string {
	// First handle the default value format
	if strings.HasPrefix(value, "default (") && strings.HasSuffix(value, ")") {
		return "" // Return empty string for default values
	}

	// Then handle specific display values
	switch value {
	case "none (-N)":
		return sessionTypeNone
	case "subsystem (-s)":
		return sessionTypeSubsystem
	case "default":
		return sessionTypeDefault
	default:
		return value
	}
}

// handleSaveButton is a wrapper for button callback (no return value)
func (sf *ServerForm) handleSaveButton() {
	sf.handleSave()
}

// handleSave validates and saves the form, returns true if successful
func (sf *ServerForm) handleSave() bool {
	// First validate all fields with the new validation system
	if !sf.validateAllFields() {
		// Show validation errors
		if sf.app != nil {
			errors := sf.validation.GetAllErrors()
			if len(errors) > 0 {
				// Limit the number of errors to display to prevent overflow
				maxErrorsToShow := 5
				truncated := false
				if len(errors) > maxErrorsToShow {
					errors = errors[:maxErrorsToShow]
					truncated = true
				}

				// Build error message
				errorMsg := fmt.Sprintf("Validation failed (%d error%s):\n\n",
					sf.validation.GetErrorCount(),
					func() string {
						if sf.validation.GetErrorCount() == 1 {
							return ""
						}
						return "s"
					}())

				for i, err := range errors {
					errorMsg += fmt.Sprintf("%d. %s\n", i+1, err)
				}

				if truncated {
					errorMsg += fmt.Sprintf("\n... and %d more error%s",
						sf.validation.GetErrorCount()-maxErrorsToShow,
						func() string {
							if sf.validation.GetErrorCount()-maxErrorsToShow == 1 {
								return ""
							}
							return "s"
						}())
				}

				// Use tview's built-in Modal
				modal := tview.NewModal().
					SetText(errorMsg).
					AddButtons([]string{"OK"}).
					SetDoneFunc(func(buttonIndex int, buttonLabel string) {
						sf.app.SetRoot(sf.Flex, true)
					})

				sf.app.SetRoot(modal, true)
			}
		}
		return false // Validation failed
	}

	data := sf.getFormData()

	// Reset title and border (validation already done above)
	sf.formPanel.SetTitle(" " + sf.titleForMode() + " ")
	sf.formPanel.SetBorderColor(tcell.Color238)

	server := sf.dataToServer(data)
	if sf.onSave != nil {
		sf.onSave(server, sf.original)
	}
	return true // Save successful
}

func (sf *ServerForm) handleCancel() {
	// Check if there are unsaved changes
	if sf.hasUnsavedChanges() {
		// If app reference is available, show confirmation dialog
		if sf.app != nil {
			modal := tview.NewModal().
				SetText("You have unsaved changes. Are you sure you want to exit?").
				AddButtons([]string{"[yellow]S[-]ave", "[yellow]D[-]iscard", "[yellow]C[-]ancel"}).
				SetDoneFunc(func(buttonIndex int, buttonLabel string) {
					switch buttonIndex {
					case 0: // Save
						// Try to save, if successful it will exit
						if sf.handleSave() {
							// Save successful, modal will be replaced by onSave callback
						} else {
							// Validation failed, return to form
							sf.app.SetRoot(sf.Flex, true)
						}
					case 1: // Discard
						if sf.onCancel != nil {
							sf.onCancel()
						}
					case 2: // Cancel
						// Restore the form view
						sf.app.SetRoot(sf.Flex, true)
					}
				})

			// Set up keyboard shortcuts for the modal
			modal.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
				switch event.Rune() {
				case 's', 'S':
					if sf.handleSave() {
						// Save successful
					} else {
						// Validation failed, return to form
						sf.app.SetRoot(sf.Flex, true)
					}
					return nil
				case 'd', 'D':
					if sf.onCancel != nil {
						sf.onCancel()
					}
					return nil
				case 'c', 'C':
					sf.app.SetRoot(sf.Flex, true)
					return nil
				}
				return event
			})

			// Show modal
			sf.app.SetRoot(modal, true)
		} else if sf.onCancel != nil {
			// No app reference, fallback to direct cancel (shouldn't happen in normal use)
			sf.onCancel()
		}
	} else {
		// No unsaved changes, just exit
		if sf.onCancel != nil {
			sf.onCancel()
		}
	}
}

// hasUnsavedChanges checks if current form data differs from original
func (sf *ServerForm) hasUnsavedChanges() bool {
	// If creating new server, any non-empty required fields mean changes
	if sf.mode == ServerFormAdd {
		data := sf.getFormData()
		return data.Alias != "" || data.Host != "" || data.User != ""
	}

	// If editing, compare with original
	if sf.original == nil {
		return false
	}

	currentData := sf.getFormData()
	currentServer := sf.dataToServer(currentData)

	// Use DeepEqual for simple comparison first
	if reflect.DeepEqual(currentServer, *sf.original) {
		return false
	}

	// If DeepEqual says they're different, use our custom comparison
	// that handles nil vs empty slice and other normalization
	return sf.serversDiffer(currentServer, *sf.original)
}

// serversDiffer compares two servers for differences using reflection
func (sf *ServerForm) serversDiffer(a, b domain.Server) bool {
	// Use reflection to compare all fields
	valA := reflect.ValueOf(a)
	valB := reflect.ValueOf(b)
	typeA := valA.Type()

	// Fields to skip during comparison (lazyssh metadata fields)
	skipFields := map[string]bool{
		"Aliases":  true, // Computed field
		"LastSeen": true, // Metadata field
		"PinnedAt": true, // Metadata field
		"SSHCount": true, // Metadata field
	}

	// Iterate through all fields
	for i := 0; i < valA.NumField(); i++ {
		fieldA := valA.Field(i)
		fieldB := valB.Field(i)
		fieldName := typeA.Field(i).Name

		// Skip unexported fields and metadata fields
		if !fieldA.CanInterface() || skipFields[fieldName] {
			continue
		}

		// Compare based on field type
		differs := false
		switch fieldA.Kind() {
		case reflect.String:
			if fieldA.String() != fieldB.String() {
				differs = true
			}
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			if fieldA.Int() != fieldB.Int() {
				differs = true
			}
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			if fieldA.Uint() != fieldB.Uint() {
				differs = true
			}
		case reflect.Slice:
			if !sf.slicesEqual(fieldA, fieldB) {
				differs = true
			}
		case reflect.Bool:
			if fieldA.Bool() != fieldB.Bool() {
				differs = true
			}
		case reflect.Float32, reflect.Float64:
			if fieldA.Float() != fieldB.Float() {
				differs = true
			}
		case reflect.Complex64, reflect.Complex128:
			if fieldA.Complex() != fieldB.Complex() {
				differs = true
			}
		case reflect.Array, reflect.Chan, reflect.Func, reflect.Interface,
			reflect.Map, reflect.Ptr, reflect.Struct, reflect.UnsafePointer, reflect.Invalid:
			// For these types, use reflect.DeepEqual
			if !reflect.DeepEqual(fieldA.Interface(), fieldB.Interface()) {
				differs = true
			}
		}

		if differs {
			return true
		}
	}

	return false
}

// slicesEqual compares two reflect.Value slices for equality
func (sf *ServerForm) slicesEqual(a, b reflect.Value) bool {
	// Handle nil slices - treat nil and empty slice as equal
	if a.IsNil() && b.IsNil() {
		return true
	}
	if a.IsNil() && b.Len() == 0 {
		return true
	}
	if b.IsNil() && a.Len() == 0 {
		return true
	}

	if a.Len() != b.Len() {
		return false
	}

	for i := 0; i < a.Len(); i++ {
		// For string slices
		if a.Index(i).Kind() == reflect.String {
			if a.Index(i).String() != b.Index(i).String() {
				return false
			}
		} else {
			// For other types, use DeepEqual
			if !reflect.DeepEqual(a.Index(i).Interface(), b.Index(i).Interface()) {
				return false
			}
		}
	}

	return true
}

func (sf *ServerForm) dataToServer(data ServerFormData) domain.Server {
	port := 22
	if data.Port != "" {
		if n, err := strconv.Atoi(data.Port); err == nil && n > 0 {
			port = n
		}
	}

	// Use nil for empty slices to match original state
	var tags []string
	if data.Tags != "" {
		for _, t := range strings.Split(data.Tags, ",") {
			if s := strings.TrimSpace(t); s != "" {
				tags = append(tags, s)
			}
		}
	}

	var keys []string
	if data.Key != "" {
		parts := strings.Split(data.Key, ",")
		for _, p := range parts {
			if k := strings.TrimSpace(p); k != "" {
				keys = append(keys, k)
			}
		}
	}

	// Helper to split comma-separated values
	splitComma := func(s string) []string {
		if s == "" {
			return nil
		}
		var result []string
		for _, item := range strings.Split(s, ",") {
			if trimmed := strings.TrimSpace(item); trimmed != "" {
				result = append(result, trimmed)
			}
		}
		return result
	}

	server := domain.Server{
		Alias:                data.Alias,
		Host:                 data.Host,
		User:                 data.User,
		Port:                 port,
		IdentityFiles:        keys,
		Tags:                 tags,
		ProxyJump:            data.ProxyJump,
		ProxyCommand:         data.ProxyCommand,
		RemoteCommand:        data.RemoteCommand,
		RequestTTY:           data.RequestTTY,
		SessionType:          data.SessionType,
		ConnectTimeout:       data.ConnectTimeout,
		ConnectionAttempts:   data.ConnectionAttempts,
		BindAddress:          data.BindAddress,
		BindInterface:        data.BindInterface,
		AddressFamily:        data.AddressFamily,
		ExitOnForwardFailure: data.ExitOnForwardFailure,
		LocalForward:         splitComma(data.LocalForward),
		RemoteForward:        splitComma(data.RemoteForward),
		DynamicForward:       splitComma(data.DynamicForward),
		ClearAllForwardings:  data.ClearAllForwardings,
		// Public key
		PubkeyAuthentication: data.PubkeyAuthentication,
		IdentitiesOnly:       data.IdentitiesOnly,
		// SSH Agent
		AddKeysToAgent: data.AddKeysToAgent,
		IdentityAgent:  data.IdentityAgent,
		// Password & Interactive
		PasswordAuthentication:       data.PasswordAuthentication,
		KbdInteractiveAuthentication: data.KbdInteractiveAuthentication,
		NumberOfPasswordPrompts:      data.NumberOfPasswordPrompts,
		// Advanced
		PreferredAuthentications:    data.PreferredAuthentications,
		ForwardAgent:                data.ForwardAgent,
		ForwardX11:                  data.ForwardX11,
		ForwardX11Trusted:           data.ForwardX11Trusted,
		ControlMaster:               data.ControlMaster,
		ControlPath:                 data.ControlPath,
		ControlPersist:              data.ControlPersist,
		ServerAliveInterval:         data.ServerAliveInterval,
		ServerAliveCountMax:         data.ServerAliveCountMax,
		Compression:                 data.Compression,
		TCPKeepAlive:                data.TCPKeepAlive,
		BatchMode:                   data.BatchMode,
		StrictHostKeyChecking:       data.StrictHostKeyChecking,
		UserKnownHostsFile:          data.UserKnownHostsFile,
		HostKeyAlgorithms:           data.HostKeyAlgorithms,
		PubkeyAcceptedAlgorithms:    data.PubkeyAcceptedAlgorithms,
		HostbasedAcceptedAlgorithms: data.HostbasedAcceptedAlgorithms,
		MACs:                        data.MACs,
		Ciphers:                     data.Ciphers,
		KexAlgorithms:               data.KexAlgorithms,
		VerifyHostKeyDNS:            data.VerifyHostKeyDNS,
		UpdateHostKeys:              data.UpdateHostKeys,
		HashKnownHosts:              data.HashKnownHosts,
		VisualHostKey:               data.VisualHostKey,
		LocalCommand:                data.LocalCommand,
		PermitLocalCommand:          data.PermitLocalCommand,
		EscapeChar:                  data.EscapeChar,
		SendEnv:                     splitComma(data.SendEnv),
		SetEnv:                      splitComma(data.SetEnv),
		LogLevel:                    data.LogLevel,
	}

	// Preserve metadata fields from original if in edit mode
	if sf.mode == ServerFormEdit && sf.original != nil {
		server.PinnedAt = sf.original.PinnedAt
		server.LastSeen = sf.original.LastSeen
		server.SSHCount = sf.original.SSHCount
		// Also preserve Aliases (computed field)
		server.Aliases = sf.original.Aliases
	}

	return server
}

func (sf *ServerForm) OnSave(fn func(domain.Server, *domain.Server)) *ServerForm {
	sf.onSave = fn
	return sf
}

func (sf *ServerForm) OnCancel(fn func()) *ServerForm {
	sf.onCancel = fn
	return sf
}

func (sf *ServerForm) SetApp(app *tview.Application) *ServerForm {
	sf.app = app
	return sf
}

func (sf *ServerForm) SetVersionInfo(version, commit string) *ServerForm {
	sf.version = version
	sf.commit = commit
	// Build the form now that we have version info
	if sf.header == nil {
		sf.build()
	} else {
		// Rebuild header if already exists
		sf.header = NewAppHeader(sf.version, sf.commit, RepoURL)
	}
	return sf
}
