package main

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"pulsegate/internal/config"
	"pulsegate/internal/models"
	"pulsegate/internal/secret"

	"github.com/charmbracelet/bubbles/textinput"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	"golang.org/x/term"
)

type viewMode string

const (
	ViewServers       viewMode = "servers"
	ViewSettings      viewMode = "settings"
	ViewHelp          viewMode = "help"
	ViewAddServer     viewMode = "add_server"
	ViewEditServer    viewMode = "edit_server"
	ViewDeleteConfirm viewMode = "delete_confirm"
	ViewCommands      viewMode = "commands"
	ViewCommandOutput viewMode = "command_output"
)

type model struct {
	cfg      models.AppConfig
	servers  []models.Server
	selected int
	view     viewMode
	width    int
	height   int
	err      error

	addInputs           []textinput.Model
	addFocus            int
	editIndex           int
	commandSelected     int
	commandOutput       string
	commandTitle        string
	commandError        string
	serverStatus        map[int]string
	settingsSelected    int
	settingsEditingTerm bool
	settingsTermInput   textinput.Model
}

var (
	green   = lipgloss.Color("#00ff99")
	cyan    = lipgloss.Color("#33ccff")
	gray    = lipgloss.Color("#777777")
	text    = lipgloss.Color("#d7ffe9")
	dimText = lipgloss.Color("#8aa99b")
	panelBg = lipgloss.Color("#07110d")
	border  = lipgloss.Color("#00aa66")
	warn    = lipgloss.Color("#ffaa00")

	baseStyle = lipgloss.NewStyle().
			Foreground(text)

	headerStyle = lipgloss.NewStyle().
			Bold(true).
			Foreground(green).
			Border(lipgloss.RoundedBorder()).
			BorderForeground(border).
			Padding(1, 2)

	panelStyle = lipgloss.NewStyle().
			Border(lipgloss.RoundedBorder()).
			BorderForeground(border).
			Padding(1, 2)

	selectedStyle = lipgloss.NewStyle().
			Foreground(green).
			Bold(true)

	normalStyle = lipgloss.NewStyle().
			Foreground(text)

	mutedStyle = lipgloss.NewStyle().
			Foreground(gray)

	helpStyle = lipgloss.NewStyle().
			Foreground(dimText)

	badgeStyle = lipgloss.NewStyle().
			Foreground(lipgloss.Color("#001a10")).
			Background(green).
			Bold(true).
			Padding(0, 1)
)

func initialModel() model {
	configPath := getConfigPath()

	if err := ensureConfigExists(configPath); err != nil {
		return model{err: err}
	}

	cfg, err := config.LoadConfig(configPath)
	if err != nil {
		return model{err: err}
	}

	m := model{
		cfg:          cfg,
		servers:      cfg.Servers,
		selected:     0,
		view:         ViewServers,
		serverStatus: make(map[int]string),
	}

	m.initAddInputs()
	m.initSettingsInput()
	return m
}

func (m model) Init() tea.Cmd {
	return checkAllServerStatus(m.servers)
}

func (m *model) initAddInputs() {
	labels := []string{
		"Name",
		"Host",
		"User",
		"Port",
		"Group",
		"Auth (key/password)",
		"Key Path",
		"Password ID",
	}

	m.addInputs = make([]textinput.Model, len(labels))

	for i, label := range labels {
		input := textinput.New()
		input.Placeholder = label
		input.CharLimit = 120
		input.Width = 40

		switch label {
		case "Port":
			input.SetValue("22")
		case "Auth (key/password)":
			input.SetValue("key")
		case "Group":
			input.SetValue("Homelab")
		}

		if i == 0 {
			input.Focus()
		}

		m.addInputs[i] = input
	}
}

func (m *model) initSettingsInput() {
	input := textinput.New()
	input.Placeholder = "TERM Override"
	input.CharLimit = 80
	input.Width = 32
	input.SetValue(m.cfg.Settings.Terminal.Term)

	m.settingsTermInput = input
}

func (m *model) saveNewServer() error {
	port, err := strconv.Atoi(m.addInputs[3].Value())
	if err != nil {
		port = 22
	}

	server := models.Server{
		Name:       m.addInputs[0].Value(),
		Host:       m.addInputs[1].Value(),
		User:       m.addInputs[2].Value(),
		Port:       port,
		Group:      m.addInputs[4].Value(),
		Auth:       m.addInputs[5].Value(),
		Key:        m.addInputs[6].Value(),
		PasswordID: m.addInputs[7].Value(),
		KittyFix:   true,
	}

	if server.Name == "" || server.Host == "" || server.User == "" {
		return fmt.Errorf("name, host und user sind pflichtfelder")
	}

	if server.Auth == "" {
		server.Auth = "key"
	}

	if server.Auth == "password" && server.PasswordID == "" {
		server.PasswordID = strings.ToLower(server.Name) + "-" + server.User
	}

	m.cfg.Servers = append(m.cfg.Servers, server)
	m.servers = m.cfg.Servers

	err = config.SaveConfig(getConfigPath(), m.cfg)
	if err != nil {
		return err
	}

	m.selected = len(m.servers) - 1
	m.initAddInputs()
	m.view = ViewServers

	return nil
}

type quickCommandResultMsg struct {
	Title  string
	Output string
	Error  string
}

type serverStatusMsg struct {
	Index  int
	Status string
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	if m.err != nil {
		return m, nil
	}

	switch msg := msg.(type) {
	case tea.WindowSizeMsg:
		m.width = msg.Width
		m.height = msg.Height

	case quickCommandResultMsg:
		m.commandTitle = msg.Title
		m.commandOutput = msg.Output
		m.commandError = msg.Error
		m.view = ViewCommandOutput
		return m, nil

	case serverStatusMsg:
		if m.serverStatus == nil {
			m.serverStatus = make(map[int]string)
		}

		m.serverStatus[msg.Index] = msg.Status
		return m, nil

	case tea.KeyMsg:

		// Command Output offen lassen, bis du ihn wegdrückst
		if m.view == ViewCommandOutput {
			switch msg.String() {
			case "q", "esc", "enter":
				m.view = ViewCommands
				return m, nil

			case "ctrl+c":
				return m, tea.Quit
			}
		}

		// Add/Edit Formular
		if m.view == ViewAddServer || m.view == ViewEditServer {
			switch msg.String() {
			case "ctrl+c":
				return m, tea.Quit

			case "esc", "q":
				m.view = ViewServers
				return m, nil

			case "tab", "down":
				m.addInputs[m.addFocus].Blur()
				m.addFocus = (m.addFocus + 1) % len(m.addInputs)
				m.addInputs[m.addFocus].Focus()
				return m, nil

			case "r":
				return m, checkAllServerStatus(m.servers)

			case "shift+tab", "up":
				m.addInputs[m.addFocus].Blur()
				m.addFocus--
				if m.addFocus < 0 {
					m.addFocus = len(m.addInputs) - 1
				}
				m.addInputs[m.addFocus].Focus()
				return m, nil

			case "enter":
				if m.addFocus < len(m.addInputs)-1 {
					m.addInputs[m.addFocus].Blur()
					m.addFocus++
					m.addInputs[m.addFocus].Focus()
					return m, nil
				}

				var err error
				if m.view == ViewAddServer {
					err = m.saveNewServer()
				} else {
					err = m.saveEditedServer()
				}

				if err != nil {
					m.err = err
				}
				return m, nil
			}

			var cmd tea.Cmd
			m.addInputs[m.addFocus], cmd = m.addInputs[m.addFocus].Update(msg)
			return m, cmd
		}

		// Delete Confirm
		if m.view == ViewDeleteConfirm {
			switch msg.String() {
			case "y", "Y", "j":
				err := m.deleteSelectedServer()
				if err != nil {
					m.err = err
				}
				return m, nil

			case "n", "N", "esc", "q":
				m.view = ViewServers
				return m, nil
			}
		}

		if m.view == ViewSettings {
			if m.settingsEditingTerm {
				switch msg.String() {
				case "ctrl+c":
					return m, tea.Quit

				case "esc":
					m.settingsEditingTerm = false
					m.settingsTermInput.Blur()
					m.settingsTermInput.SetValue(m.cfg.Settings.Terminal.Term)
					return m, nil

				case "enter":
					m.cfg.Settings.Terminal.Term = strings.TrimSpace(m.settingsTermInput.Value())
					if err := m.saveSettings(); err != nil {
						m.err = err
					}
					m.settingsEditingTerm = false
					m.settingsTermInput.Blur()
					return m, nil
				}

				var cmd tea.Cmd
				m.settingsTermInput, cmd = m.settingsTermInput.Update(msg)
				return m, cmd
			}

			switch msg.String() {
			case "ctrl+c":
				return m, tea.Quit

			case "q", "esc":
				m.view = ViewServers
				return m, nil

			case "up", "k":
				if m.settingsSelected > 0 {
					m.settingsSelected--
				}
				return m, nil

			case "down", "j":
				if m.settingsSelected < settingsOptionCount()-1 {
					m.settingsSelected++
				}
				return m, nil

			case "enter", " ":
				switch m.settingsSelected {
				case 0:
					m.cfg.Settings.Terminal.EnableKittyFix = !m.cfg.Settings.Terminal.EnableKittyFix
					if err := m.saveSettings(); err != nil {
						m.err = err
					}
				case 1:
					m.settingsEditingTerm = true
					m.settingsTermInput.SetValue(m.cfg.Settings.Terminal.Term)
					m.settingsTermInput.Focus()
				case 2:
					m.cfg.Settings.Theme = nextTheme(m.cfg.Settings.Theme)
					if err := m.saveSettings(); err != nil {
						m.err = err
					}
				}
				return m, nil
			}
		}

		// Normale Navigation
		switch msg.String() {
		case "ctrl+c":
			return m, tea.Quit

		case "q":
			if m.view != ViewServers {
				m.view = ViewServers
				return m, nil
			}
			return m, tea.Quit

		case "tab":
			m.view = nextView(m.view)

		case "a":
			m.view = ViewAddServer
			m.addFocus = 0
			m.initAddInputs()
			return m, nil

		case "e":
			if m.view == ViewServers && len(m.servers) > 0 {
				m.editIndex = m.selected
				m.view = ViewEditServer
				m.loadServerIntoForm(m.servers[m.selected])
			}
			return m, nil

		case "d":
			if m.view == ViewServers && len(m.servers) > 0 {
				m.view = ViewDeleteConfirm
			}
			return m, nil

		case "c":
			if len(m.servers) > 0 {
				m.view = ViewCommands
				m.commandSelected = 0
			}
			return m, nil

		case "s":
			m.view = ViewSettings
			m.settingsEditingTerm = false
			m.settingsTermInput.Blur()
			return m, nil

		case "h":
			m.view = ViewHelp
			return m, nil

		case "up", "k":
			if m.view == ViewServers && m.selected > 0 {
				m.selected--
			}
			if m.view == ViewCommands && m.commandSelected > 0 {
				m.commandSelected--
			}

		case "down", "j":
			if m.view == ViewServers && m.selected < len(m.servers)-1 {
				m.selected++
			}
			if m.view == ViewCommands && m.commandSelected < len(m.cfg.QuickCommands)-1 {
				m.commandSelected++
			}

		case "enter":
			if m.view == ViewServers && len(m.servers) > 0 {
				server := m.servers[m.selected]
				return m, connectSSH(server, m.cfg.Settings)
			}

			if m.view == ViewCommands && len(m.servers) > 0 && len(m.cfg.QuickCommands) > 0 {
				server := m.servers[m.selected]
				quick := m.cfg.QuickCommands[m.commandSelected]
				return m, runQuickCommand(server, m.cfg.Settings, quick)
			}
		}
	}

	return m, nil
}

func nextView(v viewMode) viewMode {
	switch v {
	case ViewServers:
		return ViewSettings
	case ViewSettings:
		return ViewHelp
	default:
		return ViewServers
	}
}

func (m model) View() string {
	if m.err != nil {
		return "Fehler: " + m.err.Error()
	}

	if m.width == 0 {
		m.width = 100
	}
	if m.height == 0 {
		m.height = 30
	}

	header := m.renderHeader()

	var right string
	switch m.view {
	case ViewServers:
		right = m.renderServerList()
	case ViewSettings:
		right = m.renderSettingsContent()
	case ViewHelp:
		right = m.renderHelpContent()
	case ViewAddServer:
		right = m.renderAddServerContent()
	case ViewEditServer:
		right = m.renderEditServerContent()
	case ViewDeleteConfirm:
		right = m.renderDeleteConfirmContent()
	case ViewCommands:
		right = m.renderCommandsContent()
	case ViewCommandOutput:
		right = m.renderCommandOutputContent()
	default:
		right = m.renderServerList()
	}

	body := lipgloss.JoinHorizontal(
		lipgloss.Top,
		m.renderNavigation(),
		"  ",
		right,
	)

	footer := helpStyle.Render("↑/↓ Auswahl  Enter Verbinden  a Hinzufügen  e Editieren  d Löschen  c Commands  r Status refresh  Tab Ansicht  q Zurück/Beenden")

	content := lipgloss.JoinVertical(
		lipgloss.Left,
		header,
		body,
		footer,
	)

	return baseStyle.Render(content)
}

func (m model) renderHeader() string {
	title := "󰣀 PulseGate"
	subtitle := fmt.Sprintf(
		"Homelab SSH Control Center  •  Server: %d  •  Theme: %s  •  TERM: %s",
		len(m.servers),
		m.cfg.Settings.Theme,
		m.cfg.Settings.Terminal.Term,
	)

	return headerStyle.
		Width(max(m.width-6, 60)).
		Render(title + "\n" + mutedStyle.Render(subtitle))
}

/*func (m model) renderServerView() string {
	left := m.renderNavigation()
	right := m.renderServerList()

	return lipgloss.JoinHorizontal(lipgloss.Top, left, "  ", right)
}*/

func (m model) renderNavigation() string {
	items := []struct {
		icon string
		name string
		view viewMode
	}{
		{"󰒋", "Server", ViewServers},
		{"󰐕", "Add Server", ViewAddServer},
		{"󰢹", "Settings", ViewSettings},
		{"󰋖", "Help", ViewHelp},
		{"󰘳", "Commands", ViewCommands},
	}

	var lines []string
	lines = append(lines, badgeStyle.Render(" NAVIGATION "))
	lines = append(lines, "")

	for _, item := range items {
		line := fmt.Sprintf("%s  %s", item.icon, item.name)
		if m.view == item.view {
			lines = append(lines, selectedStyle.Render("> "+line))
		} else {
			lines = append(lines, normalStyle.Render("  "+line))
		}
	}

	return panelStyle.
		Width(24).
		Height(max(m.height-9, 12)).
		Render(strings.Join(lines, "\n"))
}

func (m model) renderServerList() string {
	var lines []string
	lines = append(lines, badgeStyle.Render(" SERVERS "))
	lines = append(lines, "")

	for i, server := range m.servers {
		authIcon := "󰌾"
		status := m.serverStatus[i]
		statusRendered := statusStyle(status).Render(statusIcon(status))
		if server.Auth == "key" {
			authIcon = "󰌆"
		}

		kitty := ""
		if server.KittyFix {
			kitty = " 󰄛 kitty"
		}

		statusText := ""
		if status == "online" {
			statusText = " ssh"
		} else if status == "offline" {
			statusText = " off"
		}

		line := fmt.Sprintf(
			"%s%s %s %s  %s@%s:%d  [%s]%s",
			statusRendered,
			statusText,
			authIcon,
			server.Name,
			server.User,
			server.Host,
			server.Port,
			server.Group,
			kitty,
		)

		if i == m.selected {
			lines = append(lines, selectedStyle.Render("> "+line))
		} else {
			lines = append(lines, normalStyle.Render("  "+line))
		}
	}

	if len(m.servers) == 0 {
		lines = append(lines, mutedStyle.Render("Keine Server in config.yaml gefunden."))
	}

	width := max(m.width-36, 50)

	return panelStyle.
		Width(width).
		Height(max(m.height-9, 12)).
		Render(strings.Join(lines, "\n"))
}

func (m model) renderSettingsContent() string {
	kittyValue := "aus"
	if m.cfg.Settings.Terminal.EnableKittyFix {
		kittyValue = "an"
	}

	termValue := m.cfg.Settings.Terminal.Term
	if termValue == "" {
		termValue = "xterm-256color"
	}

	themeValue := m.cfg.Settings.Theme
	if themeValue == "" {
		themeValue = "neon-green"
	}

	options := []string{
		fmt.Sprintf("Kitty Fix global: %s", kittyValue),
		fmt.Sprintf("TERM Override:    %s", termValue),
		fmt.Sprintf("Theme:            %s", themeValue),
	}

	lines := []string{
		badgeStyle.Render(" SETTINGS "),
		"",
		selectedStyle.Render("Terminal"),
	}

	for i, option := range options {
		if i == 1 && m.settingsEditingTerm {
			option = "TERM Override:    " + m.settingsTermInput.View()
		}

		if i == m.settingsSelected {
			lines = append(lines, selectedStyle.Render("> "+option))
		} else {
			lines = append(lines, normalStyle.Render("  "+option))
		}
	}

	lines = append(lines,
		"",
		selectedStyle.Render("Hinweis"),
		"  Wenn Kitty Fix aktiv ist, startet SSH mit dem gewählten TERM-Wert.",
		"  Das verhindert auf Ubuntu/Debian oft:",
		"  'Error opening terminal: xterm-kitty'",
		"",
		mutedStyle.Render("↑/↓ Auswahl  Enter/Space ändern  Esc/q zurück"),
	)

	if m.settingsEditingTerm {
		lines = append(lines, mutedStyle.Render("TERM bearbeiten: Enter speichern  Esc abbrechen"))
	}

	return panelStyle.
		Width(max(m.width-6, 70)).
		Height(max(m.height-9, 14)).
		Render(strings.Join(lines, "\n"))
}

func settingsOptionCount() int {
	return 3
}

func nextTheme(current string) string {
	themes := []string{"neon-green", "cyan", "plain"}

	for i, theme := range themes {
		if current == theme {
			return themes[(i+1)%len(themes)]
		}
	}

	return themes[0]
}

func (m *model) saveSettings() error {
	if m.cfg.Settings.Terminal.Term == "" {
		m.cfg.Settings.Terminal.Term = "xterm-256color"
		m.settingsTermInput.SetValue(m.cfg.Settings.Terminal.Term)
	}

	if m.cfg.Settings.Theme == "" {
		m.cfg.Settings.Theme = "neon-green"
	}

	return config.SaveConfig(getConfigPath(), m.cfg)
}

func (m model) renderHelpContent() string {
	lines := []string{
		badgeStyle.Render(" HELP "),
		"",
		"Enter       Ausgewählten Server verbinden",
		"↑/↓ / j/k   Server auswählen",
		"Tab         Ansicht wechseln",
		"s           Settings öffnen",
		"h           Hilfe öffnen",
		"q           Zurück oder Beenden",
		"",
		selectedStyle.Render("Kitty Fix"),
		"Wenn du per Kitty auf Ubuntu SSH nutzt und nano/clear Fehler machen:",
		"TERM=xterm-256color hilft meistens.",
	}

	return panelStyle.
		Width(max(m.width-6, 70)).
		Height(max(m.height-9, 14)).
		Render(strings.Join(lines, "\n"))
}

func connectSSH(server models.Server, settings models.Settings) tea.Cmd {
	switch server.Auth {
	case "key":
		args := []string{
			"-p", strconv.Itoa(server.Port),
		}

		if server.Key != "" {
			args = append(args, "-i", expandHome(server.Key))
		}

		args = append(args, server.User+"@"+server.Host)

		cmd := exec.Command("ssh", args...)
		cmd.Env = buildSSHEnv(server, settings)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		return tea.ExecProcess(cmd, func(err error) tea.Msg {
			return err
		})

	case "password":
		password, err := secret.GetPassword(server.PasswordID)

		if err != nil {
			fmt.Printf("\nPasswort für %s@%s: ", server.User, server.Host)

			pw, inputErr := term.ReadPassword(int(os.Stdin.Fd()))
			fmt.Println()

			if inputErr != nil {
				return func() tea.Msg {
					return inputErr
				}
			}

			password = string(pw)

			saveErr := secret.SavePassword(server.PasswordID, password)
			if saveErr != nil {
				fmt.Println("Fehler beim Speichern:", saveErr)
			} else {
				fmt.Println("Passwort gespeichert.")
			}
		}

		args := []string{
			"-e",
			"ssh",
			"-p", strconv.Itoa(server.Port),
			server.User + "@" + server.Host,
		}

		cmd := exec.Command("sshpass", args...)
		cmd.Env = append(buildSSHEnv(server, settings), "SSHPASS="+password)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		return tea.ExecProcess(cmd, func(err error) tea.Msg {
			return err
		})

	default:
		return func() tea.Msg {
			return fmt.Errorf("unbekannte auth methode: %s", server.Auth)
		}
	}
}

func buildSSHEnv(server models.Server, settings models.Settings) []string {
	env := os.Environ()

	if settings.Terminal.EnableKittyFix && server.KittyFix {
		termValue := settings.Terminal.Term
		if termValue == "" {
			termValue = "xterm-256color"
		}

		env = append(env, "TERM="+termValue)
	}

	return env
}

func expandHome(path string) string {
	if len(path) >= 2 && path[:2] == "~/" {
		home, _ := os.UserHomeDir()
		return home + path[1:]
	}
	return path
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func (m *model) loadServerIntoForm(server models.Server) {
	m.initAddInputs()

	m.addInputs[0].SetValue(server.Name)
	m.addInputs[1].SetValue(server.Host)
	m.addInputs[2].SetValue(server.User)
	m.addInputs[3].SetValue(strconv.Itoa(server.Port))
	m.addInputs[4].SetValue(server.Group)
	m.addInputs[5].SetValue(server.Auth)
	m.addInputs[6].SetValue(server.Key)
	m.addInputs[7].SetValue(server.PasswordID)

	m.addFocus = 0
	m.addInputs[0].Focus()
}

func (m *model) saveEditedServer() error {
	if m.editIndex < 0 || m.editIndex >= len(m.servers) {
		return fmt.Errorf("ungültiger server index")
	}

	port, err := strconv.Atoi(m.addInputs[3].Value())
	if err != nil {
		port = 22
	}

	server := models.Server{
		Name:       m.addInputs[0].Value(),
		Host:       m.addInputs[1].Value(),
		User:       m.addInputs[2].Value(),
		Port:       port,
		Group:      m.addInputs[4].Value(),
		Auth:       m.addInputs[5].Value(),
		Key:        m.addInputs[6].Value(),
		PasswordID: m.addInputs[7].Value(),
		KittyFix:   true,
	}

	if server.Name == "" || server.Host == "" || server.User == "" {
		return fmt.Errorf("name, host und user sind pflichtfelder")
	}

	if server.Auth == "" {
		server.Auth = "key"
	}

	if server.Auth == "password" && server.PasswordID == "" {
		server.PasswordID = strings.ToLower(server.Name) + "-" + server.User
	}

	m.cfg.Servers[m.editIndex] = server
	m.servers = m.cfg.Servers

	err = config.SaveConfig(getConfigPath(), m.cfg)
	if err != nil {
		return err
	}

	m.selected = m.editIndex
	m.view = ViewServers
	m.initAddInputs()

	return nil
}

func (m *model) deleteSelectedServer() error {
	if m.selected < 0 || m.selected >= len(m.servers) {
		return fmt.Errorf("kein gültiger server ausgewählt")
	}

	m.cfg.Servers = append(
		m.cfg.Servers[:m.selected],
		m.cfg.Servers[m.selected+1:]...,
	)

	m.servers = m.cfg.Servers

	if m.selected >= len(m.servers) && m.selected > 0 {
		m.selected--
	}

	err := config.SaveConfig(getConfigPath(), m.cfg)
	if err != nil {
		return err
	}

	m.view = ViewServers
	return nil
}

func (m model) renderEditServerContent() string {
	return m.renderServerFormContent(" EDIT SERVER ", "Server bearbeiten")
}

func (m model) renderAddServerContent() string {
	return m.renderServerFormContent(" ADD SERVER ", "Neuen SSH-Server hinzufügen")
}

func (m model) renderServerFormContent(badge string, title string) string {
	lines := []string{
		badgeStyle.Render(badge),
		"",
		title,
		"",
	}

	labels := []string{
		"Name",
		"Host",
		"User",
		"Port",
		"Group",
		"Auth",
		"Key Path",
		"Password ID",
	}

	for i, input := range m.addInputs {
		label := labels[i]

		if i == m.addFocus {
			lines = append(lines, selectedStyle.Render("> "+label))
		} else {
			lines = append(lines, normalStyle.Render("  "+label))
		}

		lines = append(lines, "  "+input.View())
		lines = append(lines, "")
	}

	lines = append(lines, mutedStyle.Render("Enter: nächstes Feld / speichern  Tab: weiter  Esc/q: abbrechen"))
	lines = append(lines, mutedStyle.Render("Auth: key oder password"))

	return panelStyle.
		Width(max(m.width-36, 60)).
		Height(max(m.height-9, 18)).
		Render(strings.Join(lines, "\n"))
}

func (m model) renderCommandOutputContent() string {
	lines := []string{
		badgeStyle.Render(" COMMAND OUTPUT "),
		"",
		selectedStyle.Render(m.commandTitle),
		"",
	}

	if m.commandError != "" {
		lines = append(lines, warnStyle().Render("Fehler: "+m.commandError))
		lines = append(lines, "")
	}

	output := strings.TrimSpace(m.commandOutput)
	if output == "" {
		output = "Keine Ausgabe."
	}

	lines = append(lines, output)
	lines = append(lines, "")
	lines = append(lines, mutedStyle.Render("q / Esc / Enter: zurück zu Quick Commands"))

	return panelStyle.
		Width(max(m.width-36, 60)).
		Height(max(m.height-9, 14)).
		Render(strings.Join(lines, "\n"))
}

func (m model) renderCommandsContent() string {
	lines := []string{
		badgeStyle.Render(" QUICK COMMANDS "),
		"",
	}

	if len(m.servers) == 0 {
		lines = append(lines, mutedStyle.Render("Kein Server ausgewählt."))
	} else {
		server := m.servers[m.selected]
		lines = append(lines, fmt.Sprintf("Server: %s  %s@%s:%d", server.Name, server.User, server.Host, server.Port))
		lines = append(lines, "")
	}

	if len(m.cfg.QuickCommands) == 0 {
		lines = append(lines, mutedStyle.Render("Keine quick_commands in config.yaml gefunden."))
	} else {
		for i, cmd := range m.cfg.QuickCommands {
			line := fmt.Sprintf("%s  →  %s", cmd.Name, cmd.Command)

			if i == m.commandSelected {
				lines = append(lines, selectedStyle.Render("> "+line))
			} else {
				lines = append(lines, normalStyle.Render("  "+line))
			}
		}
	}

	lines = append(lines, "")
	lines = append(lines, mutedStyle.Render("Enter: Command ausführen  ↑/↓ Auswahl  q: zurück"))

	return panelStyle.
		Width(max(m.width-36, 60)).
		Height(max(m.height-9, 14)).
		Render(strings.Join(lines, "\n"))
}

func runQuickCommand(server models.Server, settings models.Settings, quick models.QuickCommand) tea.Cmd {
	return func() tea.Msg {
		title := fmt.Sprintf("%s auf %s", quick.Name, server.Name)

		args := []string{
			"-p", strconv.Itoa(server.Port),
		}

		if settings.Terminal.EnableKittyFix && server.KittyFix {
			args = append(args, "-t")
		}

		var cmd *exec.Cmd

		if server.Auth == "key" {
			if server.Key != "" {
				args = append(args, "-i", expandHome(server.Key))
			}

			args = append(args, server.User+"@"+server.Host, quick.Command)

			cmd = exec.Command("ssh", args...)
			cmd.Env = buildSSHEnv(server, settings)
		} else if server.Auth == "password" {
			password, err := secret.GetPassword(server.PasswordID)
			if err != nil {
				return quickCommandResultMsg{
					Title:  title,
					Output: "",
					Error:  fmt.Sprintf("kein passwort gespeichert für %s", server.PasswordID),
				}
			}

			sshArgs := []string{
				"-e",
				"ssh",
				"-p", strconv.Itoa(server.Port),
				server.User + "@" + server.Host,
				quick.Command,
			}

			cmd = exec.Command("sshpass", sshArgs...)
			cmd.Env = append(buildSSHEnv(server, settings), "SSHPASS="+password)
		} else {
			return quickCommandResultMsg{
				Title:  title,
				Output: "",
				Error:  fmt.Sprintf("unbekannte auth methode: %s", server.Auth),
			}
		}

		output, err := cmd.CombinedOutput()

		errorText := ""
		if err != nil {
			errorText = err.Error()
		}

		return quickCommandResultMsg{
			Title:  title,
			Output: string(output),
			Error:  errorText,
		}
	}
}

func checkAllServerStatus(servers []models.Server) tea.Cmd {
	cmds := make([]tea.Cmd, 0, len(servers))

	for i, server := range servers {
		cmds = append(cmds, checkServerStatus(i, server))
	}

	return tea.Batch(cmds...)
}

func checkServerStatus(index int, server models.Server) tea.Cmd {
	return func() tea.Msg {
		port := server.Port
		if port == 0 {
			port = 22
		}

		addr := fmt.Sprintf("%s:%d", server.Host, port)

		conn, err := net.DialTimeout("tcp", addr, 1500*time.Millisecond)
		if err != nil {
			return serverStatusMsg{
				Index:  index,
				Status: "offline",
			}
		}

		_ = conn.Close()

		return serverStatusMsg{
			Index:  index,
			Status: "online",
		}
	}
}

func statusIcon(status string) string {
	switch status {
	case "online":
		return "●"
	case "offline":
		return "○"
	default:
		return "◌"
	}
}

func statusStyle(status string) lipgloss.Style {
	switch status {
	case "online":
		return lipgloss.NewStyle().Foreground(green).Bold(true)
	case "offline":
		return lipgloss.NewStyle().Foreground(gray)
	default:
		return lipgloss.NewStyle().Foreground(dimText)
	}
}

func (m model) renderDeleteConfirmContent() string {
	if len(m.servers) == 0 {
		return panelStyle.Render("Kein Server zum Löschen vorhanden.")
	}

	server := m.servers[m.selected]

	lines := []string{
		badgeStyle.Render(" DELETE SERVER "),
		"",
		warnStyle().Render("Diesen Server wirklich löschen?"),
		"",
		fmt.Sprintf("Name:  %s", server.Name),
		fmt.Sprintf("Host:  %s@%s:%d", server.User, server.Host, server.Port),
		fmt.Sprintf("Group: %s", server.Group),
		"",
		selectedStyle.Render("y / j = löschen"),
		mutedStyle.Render("n / q / Esc = abbrechen"),
	}

	return panelStyle.
		Width(max(m.width-36, 60)).
		Height(max(m.height-9, 14)).
		Render(strings.Join(lines, "\n"))
}

func warnStyle() lipgloss.Style {
	return lipgloss.NewStyle().
		Foreground(warn).
		Bold(true)
}

func getConfigPath() string {
	configDir, err := os.UserConfigDir()
	if err != nil {
		home, _ := os.UserHomeDir()
		return home + "/.config/pulsegate/config.yaml"
	}

	return configDir + "/pulsegate/config.yaml"
}

func ensureConfigExists(path string) error {
	if _, err := os.Stat(path); err == nil {
		return nil
	}

	dir := strings.TrimSuffix(path, "/config.yaml")

	if err := os.MkdirAll(dir, 0700); err != nil {
		return err
	}

	example := `settings:
  theme: neon-green
  terminal:
    term: xterm-256color
    enable_kitty_fix: true

servers:
  - name: Example Server
    host: 10.0.0.10
    user: root
    port: 22
    group: Homelab
    auth: key
    key: ~/.ssh/id_ed25519
    kitty_fix: true

quick_commands:
  - name: Disk Usage
    command: df -h

  - name: RAM Usage
    command: free -h

  - name: Uptime
    command: uptime
`

	return os.WriteFile(path, []byte(example), 0600)
}

func main() {
	p := tea.NewProgram(
		initialModel(),
		tea.WithAltScreen(),
	)

	if _, err := p.Run(); err != nil {
		fmt.Println("Fehler:", err)
		os.Exit(1)
	}
}
